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                 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                 // Log all HTTP transactions.
00206                 llinfos << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
00207                         << " " << mStatusCode << " " <<  mStatusMessage << " " << delta
00208                         << "s" << llendl;
00209 
00210                 // Log Internal Server Errors
00211                 //if(mStatusCode == 500)
00212                 //{
00213                 //      llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" 
00214                 //                      << llendl;
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                         // should never ever happen!
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 //      PUMP_DEBUG; // unreachable
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 // virtual
00266 LLHTTPPipe::Response::~Response()
00267 {
00268 }
00269 
00270 void LLHTTPPipe::Response::nullPipe()
00271 {
00272         mPipe = NULL;
00273 }
00274 
00275 // virtual
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 // virtual
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         /* @name LLIOPipe virtual implementations
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 // virtual
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                 //mGotEOS = true;
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         /* @name LLIOPipe virtual implementations
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         // handle the urls
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 // virtual
00514 LLHTTPResponder::~LLHTTPResponder()
00515 {
00516         LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00517         //lldebugs << "destroying LLHTTPResponder" << llendl;
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 // virtual
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         // parsing headers
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];  /*Flawfinder: ignore*/
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];   /*Flawfinder: ignore*/
00586                 while(seg_iter != buffer->endSegment())
00587                 {
00588                         memcpy(buf, (*seg_iter).data(), (*seg_iter).size());      /*Flawfinder: ignore*/
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                                                         // simple request.
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                                                 // end-o-headers
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                                         // we've found a header
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         // look for the end of stream based on 
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                 // else more bytes should be coming.
00715         }
00716 
00717         PUMP_DEBUG;
00718         if(STATE_DONE == mState)
00719         {
00720                 // hey, hey, we should have everything now, so we pass it to
00721                 // a content handler.
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                         // Copy everything after mLast read to the out.
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];   /*Flawfinder: ignore*/
00741                                 while(seg_iter != buffer->endSegment())
00742                                 {
00743                                         memcpy(buf, (*seg_iter).data(), (*seg_iter).size());      /*Flawfinder: ignore*/
00744                                         buf[(*seg_iter).size()] = '\0';
00745                                         llinfos << (*seg_iter).getChannel() << ": " << buf
00746                                                         << llendl;
00747                                         ++seg_iter;
00748                                 }
00749 #endif
00750                         }
00751 
00752                         //
00753                         // *FIX: get rid of extra bytes off the end
00754                         //
00755 
00756                         // Set up a chain which will prepend a content length and
00757                         // HTTP headers.
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                                 // this is a simple LLHTTPNode, so use LLHTTPPipe
00777                                 chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node)));
00778                         }
00779 
00780                         // Add the header - which needs to have the same
00781                         // channel information as the link before it since it
00782                         // is part of the response.
00783                         LLIOPipe* header = new LLHTTPResponseHeader;
00784                         chain.push_back(LLIOPipe::ptr_t(header));
00785 
00786                         // We need to copy all of the pipes _after_ this so
00787                         // that the response goes out correctly.
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                         // Do the final build of the chain, and send it on
00806                         // it's way.
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                 //status = mNext->process(buffer, true, pump, context);
00843                 status = STATUS_DONE;
00844         }
00845         PUMP_DEBUG;
00846         return status;
00847 }
00848 
00849 
00850 // static 
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 // static
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 // static
00900 void LLIOHTTPServer::setTimingCallback(timing_callback_t callback,
00901                                                                            void* data)
00902 {
00903         sTimingCallback = callback;
00904         sTimingCallbackData = data;
00905 }

Generated on Thu Jul 1 06:08:46 2010 for Second Life Viewer by  doxygen 1.4.7