lliohttpserver.cpp

Go to the documentation of this file.
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         // LLIOPipe API implementation.
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                 // from LLHTTPNode::Response
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() {;} // Must be accessed through LLPointer.
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     // Once we have all the data, We need to read the sd on
00146     // the the in channel, and respond on  the out channel
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                         // assume deferred unless mResponse does otherwise
00157                 mResponse = Response::create(this);
00158 
00159                 // *TODO: Babbage: Parameterize parser?
00160                 // *TODO: We should look at content-type and do the right
00161                 // thing. Phoenix 2007-12-31
00162                 LLBufferStream istr(channels, buffer.get());
00163 
00164                 static LLTimer timer;
00165                 timer.reset();
00166 
00167                 std::string verb = context[CONTEXT_REQUEST]["verb"];
00168                 if(verb == HTTP_VERB_GET)
00169                 {
00170                         mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
00171                 }
00172                 else if(verb == HTTP_VERB_PUT)
00173                 {
00174                         LLSD input;
00175                         LLSDSerialize::fromXML(input, istr);
00176                         mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
00177                 }
00178                 else if(verb == HTTP_VERB_POST)
00179                 {
00180                         LLSD input;
00181                         LLSDSerialize::fromXML(input, istr);
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                 // Log all HTTP transactions.
00206                 // TODO: Add a way to log these to their own file instead of indra.log
00207                 // It is just too spammy to be in indra.log.
00208                 lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
00209                         << " " << mStatusCode << " " <<  mStatusMessage << " " << delta
00210                         << "s" << llendl;
00211 
00212                 // Log Internal Server Errors
00213                 //if(mStatusCode == 500)
00214                 //{
00215                 //      llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" 
00216                 //                      << llendl;
00217                 //}
00218         }
00219 
00220         PUMP_DEBUG;
00221         switch (mState)
00222         {
00223                 case STATE_DELAYED:
00224                         lockChain(pump);
00225                         mState = STATE_LOCKED;
00226                         return STATUS_BREAK;
00227 
00228                 case STATE_LOCKED:
00229                         // should never ever happen!
00230                         return STATUS_ERROR;
00231 
00232                 case STATE_GOOD_RESULT:
00233                 {
00234                         context[CONTEXT_RESPONSE]["contentType"] = "application/xml";
00235                         LLBufferStream ostr(channels, buffer.get());
00236                         LLSDSerialize::toXML(mGoodResult, ostr);
00237 
00238                         return STATUS_DONE;
00239                 }
00240 
00241                 case STATE_STATUS_RESULT:
00242                 {
00243                         context[CONTEXT_RESPONSE]["contentType"] = "text/plain";
00244                         context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
00245                         context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
00246                         LLBufferStream ostr(channels, buffer.get());
00247                         ostr << mStatusMessage << std::ends;
00248 
00249                         return STATUS_DONE;
00250                 }
00251                 default:
00252                         llwarns << "LLHTTPPipe::process_impl: unexpected state "
00253                                 << mState << llendl;
00254 
00255                         return STATUS_BREAK;
00256         }
00257 //      PUMP_DEBUG; // unreachable
00258 }
00259 
00260 LLPointer<LLHTTPPipe::Response> LLHTTPPipe::Response::create(LLHTTPPipe* pipe)
00261 {
00262         LLPointer<Response> result = new Response();
00263         result->mPipe = pipe;
00264         return result;
00265 }
00266 
00267 // virtual
00268 LLHTTPPipe::Response::~Response()
00269 {
00270 }
00271 
00272 void LLHTTPPipe::Response::nullPipe()
00273 {
00274         mPipe = NULL;
00275 }
00276 
00277 // virtual
00278 void LLHTTPPipe::Response::result(const LLSD& r)
00279 {
00280         if(! mPipe)
00281         {
00282                 llwarns << "LLHTTPPipe::Response::result: NULL pipe" << llendl;
00283                 return;
00284         }
00285 
00286         mPipe->mStatusCode = 200;
00287         mPipe->mStatusMessage = "OK";
00288         mPipe->mGoodResult = r;
00289         mPipe->mState = STATE_GOOD_RESULT;
00290         mPipe->unlockChain();   
00291 }
00292 
00293 // virtual
00294 void LLHTTPPipe::Response::status(S32 code, const std::string& message)
00295 {
00296         if(! mPipe)
00297         {
00298                 llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
00299                 return;
00300         }
00301 
00302         mPipe->mStatusCode = code;
00303         mPipe->mStatusMessage = message;
00304         mPipe->mState = STATE_STATUS_RESULT;
00305         mPipe->unlockChain();
00306 }
00307 
00308 void LLHTTPPipe::lockChain(LLPumpIO* pump)
00309 {
00310         if (mChainLock != 0) { return; }
00311 
00312         mLockedPump = pump;
00313         mChainLock = pump->setLock();
00314 }
00315 
00316 void LLHTTPPipe::unlockChain()
00317 {
00318         if (mChainLock == 0) { return; }
00319 
00320         mLockedPump->clearLock(mChainLock);
00321         mLockedPump = NULL;
00322         mChainLock = 0;
00323 }
00324 
00325 
00326 
00338 class LLHTTPResponseHeader : public LLIOPipe
00339 {
00340 public:
00341         LLHTTPResponseHeader() {}
00342         virtual ~LLHTTPResponseHeader() {}
00343 
00344 protected:
00345         /* @name LLIOPipe virtual implementations
00346          */
00348 
00351         EStatus process_impl(
00352                 const LLChannelDescriptors& channels,
00353                 buffer_ptr_t& buffer,
00354                 bool& eos,
00355                 LLSD& context,
00356                 LLPumpIO* pump);
00358 
00359 protected:
00360         S32 mCode;
00361 };
00362 
00363 
00367 // virtual
00368 LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
00369         const LLChannelDescriptors& channels,
00370         buffer_ptr_t& buffer,
00371         bool& eos,
00372         LLSD& context,
00373         LLPumpIO* pump)
00374 {
00375         PUMP_DEBUG;
00376         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00377         if(eos)
00378         {
00379                 PUMP_DEBUG;
00380                 //mGotEOS = true;
00381                 std::ostringstream ostr;
00382                 std::string message = context[CONTEXT_RESPONSE]["statusMessage"];
00383                 
00384                 int code = context[CONTEXT_RESPONSE]["statusCode"];
00385                 if (code < 200)
00386                 {
00387                         code = 200;
00388                         message = "OK";
00389                 }
00390                 
00391                 ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
00392                 
00393                 std::string type = context[CONTEXT_RESPONSE]["contentType"].asString();
00394                 if (!type.empty())
00395                 {
00396                         ostr << "Content-Type: " << type << "\r\n";
00397                 }
00398                 S32 content_length = buffer->countAfter(channels.in(), NULL);
00399                 if(0 < content_length)
00400                 {
00401                         ostr << "Content-Length: " << content_length << "\r\n";
00402                 }
00403                 ostr << "\r\n";
00404 
00405                 LLChangeChannel change(channels.in(), channels.out());
00406                 std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
00407                 std::string header = ostr.str();
00408                 buffer->prepend(channels.out(), (U8*)header.c_str(), header.size());
00409                 PUMP_DEBUG;
00410                 return STATUS_DONE;
00411         }
00412         PUMP_DEBUG;
00413         return STATUS_OK;
00414 }
00415 
00416 
00417 
00426 class LLHTTPResponder : public LLIOPipe
00427 {
00428 public:
00429         LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx);
00430         ~LLHTTPResponder();
00431 
00432 protected:
00451         bool readLine(
00452                 const LLChannelDescriptors& channels,
00453                 buffer_ptr_t buffer,
00454                 U8* dest,
00455                 S32& len);
00456         
00463         void markBad(const LLChannelDescriptors& channels, buffer_ptr_t buffer);
00464 
00465 protected:
00466         /* @name LLIOPipe virtual implementations
00467          */
00469 
00472         EStatus process_impl(
00473                 const LLChannelDescriptors& channels,
00474                 buffer_ptr_t& buffer,
00475                 bool& eos,
00476                 LLSD& context,
00477                 LLPumpIO* pump);
00479 
00480 protected:
00481         enum EState
00482         {
00483                 STATE_NOTHING,
00484                 STATE_READING_HEADERS,
00485                 STATE_LOOKING_FOR_EOS,
00486                 STATE_DONE,
00487                 STATE_SHORT_CIRCUIT
00488         };
00489 
00490         LLSD mBuildContext;
00491         EState mState;
00492         U8* mLastRead;
00493         std::string mVerb;
00494         std::string mAbsPathAndQuery;
00495         std::string mPath;
00496         std::string mQuery;
00497         std::string mVersion;
00498         S32 mContentLength;
00499         LLSD mHeaders;
00500 
00501         // handle the urls
00502         const LLHTTPNode& mRootNode;
00503 };
00504 
00505 LLHTTPResponder::LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx) :
00506         mBuildContext(ctx),
00507         mState(STATE_NOTHING),
00508         mLastRead(NULL),
00509         mContentLength(0),
00510         mRootNode(tree)
00511 {
00512         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00513 }
00514 
00515 // virtual
00516 LLHTTPResponder::~LLHTTPResponder()
00517 {
00518         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00519         //lldebugs << "destroying LLHTTPResponder" << llendl;
00520 }
00521 
00522 bool LLHTTPResponder::readLine(
00523         const LLChannelDescriptors& channels,
00524         buffer_ptr_t buffer,
00525         U8* dest,
00526         S32& len)
00527 {
00528         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00529         --len;
00530         U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len);
00531         dest[len] = '\0';
00532         U8* newline = (U8*)strchr((char*)dest, '\n');
00533         if(!newline)
00534         {
00535                 if(len)
00536                 {
00537                         lldebugs << "readLine failed - too long maybe?" << llendl;
00538                         markBad(channels, buffer);
00539                 }
00540                 return false;
00541         }
00542         S32 offset = -((len - 1) - (newline - dest));
00543         ++newline;
00544         *newline = '\0';
00545         mLastRead = buffer->seek(channels.in(), last, offset);
00546         return true;
00547 }
00548 
00549 void LLHTTPResponder::markBad(
00550         const LLChannelDescriptors& channels,
00551         buffer_ptr_t buffer)
00552 {
00553         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00554         mState = STATE_SHORT_CIRCUIT;
00555         LLBufferStream out(channels, buffer.get());
00556         out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n"
00557                 << "<title>Bad Request</title>\n<body>\nBad Request.\n"
00558                 << "</body>\n</html>\n";
00559 }
00560 
00561 // virtual
00562 LLIOPipe::EStatus LLHTTPResponder::process_impl(
00563         const LLChannelDescriptors& channels,
00564         buffer_ptr_t& buffer,
00565         bool& eos,
00566         LLSD& context,
00567         LLPumpIO* pump)
00568 {
00569         PUMP_DEBUG;
00570         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00571         LLIOPipe::EStatus status = STATUS_OK;
00572 
00573         // parsing headers
00574         if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState))
00575         {
00576                 PUMP_DEBUG;
00577                 status = STATUS_BREAK;
00578                 mState = STATE_READING_HEADERS;
00579                 const S32 HEADER_BUFFER_SIZE = 1024;
00580                 char buf[HEADER_BUFFER_SIZE + 1];  /*Flawfinder: ignore*/
00581                 S32 len = HEADER_BUFFER_SIZE;
00582 
00583 #if 0
00584                 if(true)
00585                 {
00586                 LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment();
00587                 char buf[1024];   /*Flawfinder: ignore*/
00588                 while(seg_iter != buffer->endSegment())
00589                 {
00590                         memcpy(buf, (*seg_iter).data(), (*seg_iter).size());      /*Flawfinder: ignore*/
00591                         buf[(*seg_iter).size()] = '\0';
00592                         llinfos << (*seg_iter).getChannel() << ": " << buf
00593                                         << llendl;
00594                         ++seg_iter;
00595                 }
00596                 }
00597 #endif
00598                 
00599                 PUMP_DEBUG;
00600                 if(readLine(channels, buffer, (U8*)buf, len))
00601                 {
00602                         bool read_next_line = false;
00603                         bool parse_all = true;
00604                         if(mVerb.empty())
00605                         {
00606                                 read_next_line = true;
00607                                 LLMemoryStream header((U8*)buf, len);
00608                                 header >> mVerb;
00609                                 
00610                                 if((HTTP_VERB_GET == mVerb)
00611                                    || (HTTP_VERB_POST == mVerb)
00612                                    || (HTTP_VERB_PUT == mVerb)
00613                                    || (HTTP_VERB_DELETE == mVerb))
00614                                 {
00615                                         header >> mAbsPathAndQuery;
00616                                         header >> mVersion;
00617 
00618                                         lldebugs << "http request: "
00619                                                          << mVerb
00620                                                          << " " << mAbsPathAndQuery
00621                                                          << " " << mVersion << llendl;
00622 
00623                                         std::string::size_type delimiter
00624                                                 = mAbsPathAndQuery.find('?');
00625                                         if (delimiter == std::string::npos)
00626                                         {
00627                                                 mPath = mAbsPathAndQuery;
00628                                                 mQuery = "";
00629                                         }
00630                                         else
00631                                         {
00632                                                 mPath = mAbsPathAndQuery.substr(0, delimiter);
00633                                                 mQuery = mAbsPathAndQuery.substr(delimiter+1);
00634                                         }
00635 
00636                                         if(!mAbsPathAndQuery.empty())
00637                                         {
00638                                                 if(mVersion.empty())
00639                                                 {
00640                                                         // simple request.
00641                                                         parse_all = false;
00642                                                         mState = STATE_DONE;
00643                                                         mVersion.assign("HTTP/1.0");
00644                                                 }
00645                                         }
00646                                 }
00647                                 else
00648                                 {
00649                                         read_next_line = false;
00650                                         parse_all = false;
00651                                         lldebugs << "unknown http verb: " << mVerb << llendl;
00652                                         markBad(channels, buffer);
00653                                 }
00654                         }
00655                         if(parse_all)
00656                         {
00657                                 bool keep_parsing = true;
00658                                 while(keep_parsing)
00659                                 {
00660                                         if(read_next_line)
00661                                         {
00662                                                 len = HEADER_BUFFER_SIZE;       
00663                                                 readLine(channels, buffer, (U8*)buf, len);
00664                                         }
00665                                         if(0 == len)
00666                                         {
00667                                                 return status;
00668                                         }
00669                                         if(buf[0] == '\r' && buf[1] == '\n')
00670                                         {
00671                                                 // end-o-headers
00672                                                 keep_parsing = false;
00673                                                 mState = STATE_LOOKING_FOR_EOS;
00674                                                 break;
00675                                         }
00676                                         char* pos_colon = strchr(buf, ':');
00677                                         if(NULL == pos_colon)
00678                                         {
00679                                                 keep_parsing = false;
00680                                                 lldebugs << "bad header: " << buf << llendl;
00681                                                 markBad(channels, buffer);
00682                                                 break;
00683                                         }
00684                                         // we've found a header
00685                                         read_next_line = true;
00686                                         std::string name(buf, pos_colon - buf);
00687                                         std::string value(pos_colon + 2);
00688                                         LLString::toLower(name);
00689                                         if("content-length" == name)
00690                                         {
00691                                                 lldebugs << "Content-Length: " << value << llendl;
00692                                                 mContentLength = atoi(value.c_str());
00693                                         }
00694                                         else
00695                                         {
00696                                                 LLString::trimTail(value);
00697                                                 mHeaders[name] = value;
00698                                         }
00699                                 }
00700                         }
00701                 }
00702         }
00703 
00704         PUMP_DEBUG;
00705         // look for the end of stream based on 
00706         if(STATE_LOOKING_FOR_EOS == mState)
00707         {
00708                 if(0 == mContentLength)
00709                 {
00710                         mState = STATE_DONE;
00711                 }
00712                 else if(buffer->countAfter(channels.in(), mLastRead) >= mContentLength)
00713                 {
00714                         mState = STATE_DONE;
00715                 }
00716                 // else more bytes should be coming.
00717         }
00718 
00719         PUMP_DEBUG;
00720         if(STATE_DONE == mState)
00721         {
00722                 // hey, hey, we should have everything now, so we pass it to
00723                 // a content handler.
00724                 context[CONTEXT_REQUEST]["verb"] = mVerb;
00725                 const LLHTTPNode* node = mRootNode.traverse(mPath, context);
00726                 if(node)
00727                 {
00728                         //llinfos << "LLHTTPResponder::process_impl found node for "
00729                         //      << mAbsPathAndQuery << llendl;
00730 
00731                         // Copy everything after mLast read to the out.
00732                         LLBufferArray::segment_iterator_t seg_iter;
00733                         seg_iter = buffer->splitAfter(mLastRead);
00734                         if(seg_iter != buffer->endSegment())
00735                         {
00736                                 LLChangeChannel change(channels.in(), channels.out());
00737                                 ++seg_iter;
00738                                 std::for_each(seg_iter, buffer->endSegment(), change);
00739 
00740 #if 0
00741                                 seg_iter = buffer->beginSegment();
00742                                 char buf[1024];   /*Flawfinder: ignore*/
00743                                 while(seg_iter != buffer->endSegment())
00744                                 {
00745                                         memcpy(buf, (*seg_iter).data(), (*seg_iter).size());      /*Flawfinder: ignore*/
00746                                         buf[(*seg_iter).size()] = '\0';
00747                                         llinfos << (*seg_iter).getChannel() << ": " << buf
00748                                                         << llendl;
00749                                         ++seg_iter;
00750                                 }
00751 #endif
00752                         }
00753 
00754                         //
00755                         // *FIX: get rid of extra bytes off the end
00756                         //
00757 
00758                         // Set up a chain which will prepend a content length and
00759                         // HTTP headers.
00760                         LLPumpIO::chain_t chain;
00761                         chain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
00762                         context[CONTEXT_REQUEST]["path"] = mPath;
00763                         context[CONTEXT_REQUEST]["query-string"] = mQuery;
00764                         context[CONTEXT_REQUEST]["remote-host"]
00765                                 = mBuildContext["remote-host"];
00766                         context[CONTEXT_REQUEST]["remote-port"]
00767                                 = mBuildContext["remote-port"];
00768                         context[CONTEXT_REQUEST]["headers"] = mHeaders;
00769 
00770                         const LLChainIOFactory* protocolHandler
00771                                 = node->getProtocolHandler();
00772                         if (protocolHandler)
00773                         {
00774                                 protocolHandler->build(chain, context);
00775                         }
00776                         else
00777                         {
00778                                 // this is a simple LLHTTPNode, so use LLHTTPPipe
00779                                 chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node)));
00780                         }
00781 
00782                         // Add the header - which needs to have the same
00783                         // channel information as the link before it since it
00784                         // is part of the response.
00785                         LLIOPipe* header = new LLHTTPResponseHeader;
00786                         chain.push_back(LLIOPipe::ptr_t(header));
00787 
00788                         // We need to copy all of the pipes _after_ this so
00789                         // that the response goes out correctly.
00790                         LLPumpIO::links_t current_links;
00791                         pump->copyCurrentLinkInfo(current_links);
00792                         LLPumpIO::links_t::iterator link_iter = current_links.begin();
00793                         LLPumpIO::links_t::iterator links_end = current_links.end();
00794                         bool after_this = false;
00795                         for(; link_iter < links_end; ++link_iter)
00796                         {
00797                                 if(after_this)
00798                                 {
00799                                         chain.push_back((*link_iter).mPipe);
00800                                 }
00801                                 else if(this == (*link_iter).mPipe.get())
00802                                 {
00803                                         after_this = true;
00804                                 }
00805                         }
00806                         
00807                         // Do the final build of the chain, and send it on
00808                         // it's way.
00809                         LLChannelDescriptors chnl = channels;
00810                         LLPumpIO::LLLinkInfo link;
00811                         LLPumpIO::links_t links;
00812                         LLPumpIO::chain_t::iterator it = chain.begin();
00813                         LLPumpIO::chain_t::iterator end = chain.end();
00814                         while(it != end)
00815                         {
00816                                 link.mPipe = *it;
00817                                 link.mChannels = chnl;
00818                                 links.push_back(link);
00819                                 chnl = LLBufferArray::makeChannelConsumer(chnl);
00820                                 ++it;
00821                         }
00822                         pump->addChain(
00823                                 links,
00824                                 buffer,
00825                                 context,
00826                                 DEFAULT_CHAIN_EXPIRY_SECS);
00827 
00828                         status = STATUS_STOP;
00829                 }
00830                 else
00831                 {
00832                         llwarns << "LLHTTPResponder::process_impl didn't find a node for "
00833                                 << mAbsPathAndQuery << llendl;
00834                         LLBufferStream str(channels, buffer.get());
00835                         mState = STATE_SHORT_CIRCUIT;
00836                         str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n<html>\n"
00837                                 << "<title>Not Found</title>\n<body>\nNode '" << mAbsPathAndQuery
00838                                 << "' not found.\n</body>\n</html>\n";
00839                 }
00840         }
00841 
00842         if(STATE_SHORT_CIRCUIT == mState)
00843         {
00844                 //status = mNext->process(buffer, true, pump, context);
00845                 status = STATUS_DONE;
00846         }
00847         PUMP_DEBUG;
00848         return status;
00849 }
00850 
00851 
00852 // static 
00853 void LLIOHTTPServer::createPipe(LLPumpIO::chain_t& chain, 
00854         const LLHTTPNode& root, const LLSD& ctx)
00855 {
00856         chain.push_back(LLIOPipe::ptr_t(new LLHTTPResponder(root, ctx)));
00857 }
00858 
00859 
00860 class LLHTTPResponseFactory : public LLChainIOFactory
00861 {
00862 public:
00863         bool build(LLPumpIO::chain_t& chain, LLSD ctx) const
00864         {
00865                 LLIOHTTPServer::createPipe(chain, mTree, ctx);
00866                 return true;
00867         }
00868 
00869         LLHTTPNode& getRootNode() { return mTree; }
00870 
00871 private:
00872         LLHTTPNode mTree;
00873 };
00874 
00875 
00876 // static
00877 LLHTTPNode& LLIOHTTPServer::create(
00878         apr_pool_t* pool, LLPumpIO& pump, U16 port)
00879 {
00880         LLSocket::ptr_t socket = LLSocket::create(
00881         pool,
00882         LLSocket::STREAM_TCP,
00883         port);
00884     if(!socket)
00885     {
00886         llerrs << "Unable to initialize socket" << llendl;
00887     }
00888 
00889     LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
00890         boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
00891 
00892     LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
00893 
00894         LLPumpIO::chain_t chain;
00895     chain.push_back(LLIOPipe::ptr_t(server));
00896     pump.addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
00897 
00898         return factory->getRootNode();
00899 }
00900 
00901 // static
00902 void LLIOHTTPServer::setTimingCallback(timing_callback_t callback,
00903                                                                            void* data)
00904 {
00905         sTimingCallback = callback;
00906         sTimingCallbackData = data;
00907 }

Generated on Fri May 16 08:32:26 2008 for SecondLife by  doxygen 1.5.5