llhttpnode.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 #include "llhttpnode.h"
00034 
00035 #include <boost/tokenizer.hpp>
00036 
00037 #include "llstl.h"
00038 
00039 static const std::string CONTEXT_REQUEST("request");
00040 static const std::string CONTEXT_WILDCARD("wildcard");
00041 
00046 class LLHTTPNode::Impl
00047 {
00048 public:
00049         typedef std::map<std::string, LLHTTPNode*> ChildMap;
00050         
00051         ChildMap mNamedChildren;
00052         LLHTTPNode* mWildcardChild;
00053         std::string mWildcardName;
00054         std::string mWildcardKey;
00055         LLHTTPNode* mParentNode;
00056         
00057         Impl() : mWildcardChild(NULL), mParentNode(NULL) { }
00058         
00059         LLHTTPNode* findNamedChild(const std::string& name) const;
00060 };
00061 
00062 
00063 LLHTTPNode* LLHTTPNode::Impl::findNamedChild(const std::string& name) const
00064 {
00065         LLHTTPNode* child = get_ptr_in_map(mNamedChildren, name);
00066 
00067         if (!child  &&  ((name[0] == '*') || (name == mWildcardName)))
00068         {
00069                 child = mWildcardChild;
00070         }
00071         
00072         return child;
00073 }
00074 
00075 
00076 LLHTTPNode::LLHTTPNode()
00077         : impl(* new Impl)
00078 {
00079 }
00080 
00081 // virtual
00082 LLHTTPNode::~LLHTTPNode()
00083 {
00084         std::for_each(impl.mNamedChildren.begin(), impl.mNamedChildren.end(),
00085                 DeletePairedPointer());
00086 
00087         delete impl.mWildcardChild;
00088         
00089         delete &impl;
00090 }
00091 
00092 
00093 namespace {
00094         class NotImplemented
00095         {
00096         };
00097 }
00098 
00099 // virtual
00100 LLSD LLHTTPNode::get() const
00101 {
00102         throw NotImplemented();
00103 }
00104 
00105 // virtual
00106 LLSD LLHTTPNode::put(const LLSD& input) const
00107 {
00108         throw NotImplemented();
00109 }
00110 
00111 // virtual
00112 LLSD LLHTTPNode::post(const LLSD& input) const
00113 {
00114         throw NotImplemented();
00115 }
00116 
00117 
00118 // virtual
00119 void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const
00120 {
00121         try
00122         {
00123                 response->result(get());
00124         }
00125         catch (NotImplemented)
00126         {
00127                 response->methodNotAllowed();
00128         }
00129 }
00130 
00131 // virtual
00132 void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
00133 {
00134         try
00135         {
00136                 response->result(put(input));
00137         }
00138         catch (NotImplemented)
00139         {
00140                 response->methodNotAllowed();
00141         }
00142 }
00143 
00144 // virtual
00145 void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
00146 {
00147         try
00148         {
00149                 response->result(post(input));
00150         }
00151         catch (NotImplemented)
00152         {
00153                 response->methodNotAllowed();
00154         }
00155 }
00156 
00157 // virtual
00158 void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const
00159 {
00160     try
00161     {
00162         response->result(del(context));
00163     }
00164     catch (NotImplemented)
00165     {
00166         response->methodNotAllowed();
00167     }
00168 
00169 }
00170 
00171 // virtual
00172 LLSD LLHTTPNode::del(const LLSD&) const
00173 {
00174         throw NotImplemented();
00175 }
00176 
00177 
00178 // virtual
00179 LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const
00180 {
00181         LLHTTPNode* namedChild = get_ptr_in_map(impl.mNamedChildren, name);
00182         if (namedChild)
00183         {
00184                 return namedChild;
00185         }
00186         
00187         if (impl.mWildcardChild
00188         &&  impl.mWildcardChild->validate(name, context))
00189         {
00190                 context[CONTEXT_REQUEST][CONTEXT_WILDCARD][impl.mWildcardKey] = name;
00191                 return impl.mWildcardChild;
00192         }
00193         
00194         return NULL;
00195 }
00196 
00197 
00198 // virtual
00199 bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const
00200 {
00201         return remainder.size() == 0;
00202 }
00203 
00204 // virtual
00205 bool LLHTTPNode::validate(const std::string& name, LLSD& context) const
00206 {
00207         return false;
00208 }
00209 
00210 const LLHTTPNode* LLHTTPNode::traverse(
00211         const std::string& path, LLSD& context) const
00212 {
00213         typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
00214         boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
00215         tokenizer tokens(path, sep);
00216         tokenizer::iterator iter = tokens.begin();
00217         tokenizer::iterator end = tokens.end();
00218 
00219         const LLHTTPNode* node = this;
00220         for(; iter != end; ++iter)
00221         {
00222                 LLHTTPNode* child = node->getChild(*iter, context);
00223                 if(!child) 
00224                 {
00225                         lldebugs << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << llendl;
00226                         break; 
00227                 }
00228                 lldebugs << "LLHTTPNode::traverse: Found '" << *iter << "'" << llendl;
00229 
00230                 node = child;
00231         }
00232 
00233         LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
00234         for(; iter != end; ++iter)
00235         {
00236                 remainder.append(*iter);
00237         }
00238 
00239         return node->handles(remainder, context) ? node : NULL;
00240 }
00241 
00242 
00243 
00244 void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd)
00245 {
00246         typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
00247         boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
00248         tokenizer tokens(path, sep);
00249         tokenizer::iterator iter = tokens.begin();
00250         tokenizer::iterator end = tokens.end();
00251 
00252         LLHTTPNode* node = this;
00253         for(; iter != end; ++iter)
00254         {
00255                 LLHTTPNode* child = node->impl.findNamedChild(*iter);
00256                 if (!child) { break; }
00257                 node = child;
00258         }
00259         
00260         if (iter == end)
00261         {
00262                 llwarns << "LLHTTPNode::addNode: already a node that handles "
00263                         << path << llendl;
00264                 return;
00265         }
00266         
00267         while (true)
00268         {
00269                 std::string pathPart = *iter;
00270                 
00271                 ++iter;
00272                 bool lastOne = iter == end;
00273                 
00274                 LLHTTPNode* nextNode = lastOne ? nodeToAdd : new LLHTTPNode();
00275                 
00276                 switch (pathPart[0])
00277                 {
00278                         case '<':
00279                                 // *NOTE: This should really validate that it is of
00280                                 // the proper form: <wildcardkey> so that the substr()
00281                                 // generates the correct key name.
00282                                 node->impl.mWildcardChild = nextNode;
00283                                 node->impl.mWildcardName = pathPart;
00284                                 if(node->impl.mWildcardKey.empty())
00285                                 {
00286                                         node->impl.mWildcardKey = pathPart.substr(
00287                                                 1,
00288                                                 pathPart.size() - 2);
00289                                 }
00290                                 break;
00291                         case '*':
00292                                 node->impl.mWildcardChild = nextNode;
00293                                 if(node->impl.mWildcardName.empty())
00294                                 {
00295                                         node->impl.mWildcardName = pathPart;
00296                                 }
00297                                 break;
00298                         
00299                         default:
00300                                 node->impl.mNamedChildren[pathPart] = nextNode;
00301                 }
00302                 nextNode->impl.mParentNode = node;
00303 
00304                 if (lastOne) break;
00305                 node = nextNode;
00306         }
00307 }
00308 
00309 static void append_node_paths(LLSD& result,
00310         const std::string& name, const LLHTTPNode* node)
00311 {
00312         result.append(name);
00313         
00314         LLSD paths = node->allNodePaths();
00315         LLSD::array_const_iterator i = paths.beginArray();
00316         LLSD::array_const_iterator end = paths.endArray();
00317         
00318         for (; i != end; ++i)
00319         {
00320                 result.append(name + "/" + (*i).asString());
00321         }
00322 }
00323 
00324 LLSD LLHTTPNode::allNodePaths() const
00325 {
00326         LLSD result;
00327         
00328         Impl::ChildMap::const_iterator i = impl.mNamedChildren.begin();
00329         Impl::ChildMap::const_iterator end = impl.mNamedChildren.end();
00330         for (; i != end; ++i)
00331         {
00332                 append_node_paths(result, i->first, i->second);
00333         }
00334         
00335         if (impl.mWildcardChild)
00336         {
00337                 append_node_paths(result, impl.mWildcardName, impl.mWildcardChild);
00338         }
00339         
00340         return result;
00341 }
00342 
00343 
00344 const LLHTTPNode* LLHTTPNode::rootNode() const
00345 {
00346         const LLHTTPNode* node = this;
00347         
00348         while (true)
00349         {
00350                 const LLHTTPNode* next = node->impl.mParentNode;
00351                 if (!next)
00352                 {
00353                         return node;
00354                 }
00355                 node = next;
00356         }
00357 }
00358 
00359 
00360 const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const
00361 {
00362         return impl.findNamedChild(name);
00363 }
00364 
00365 LLHTTPNode::Response::~Response()
00366 {
00367 }
00368 
00369 void LLHTTPNode::Response::status(S32 code)
00370 {
00371         status(code, "Unknown Error");
00372 }
00373 
00374 void LLHTTPNode::Response::notFound(const std::string& message)
00375 {
00376         status(404, message);
00377 }
00378 
00379 void LLHTTPNode::Response::notFound()
00380 {
00381         status(404, "Not Found");
00382 }
00383 
00384 void LLHTTPNode::Response::methodNotAllowed()
00385 {
00386         status(405, "Method Not Allowed");
00387 }
00388 
00389 void LLHTTPNode::describe(Description& desc) const
00390 {
00391         desc.shortInfo("unknown service (missing describe() method)");
00392 }
00393 
00394 
00395 const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const
00396 {
00397         return NULL;
00398 }
00399 
00400 
00401 
00402 namespace
00403 {
00404     typedef std::map<std::string, LLHTTPRegistrar::NodeFactory*>  FactoryMap;
00405     
00406     FactoryMap& factoryMap()
00407     {
00408         static FactoryMap theMap;
00409         return theMap;
00410     }
00411 }
00412 
00413 LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
00414 
00415 void LLHTTPRegistrar::registerFactory(
00416     const std::string& path, NodeFactory& factory)
00417 {
00418         factoryMap()[path] = &factory;
00419 }
00420 
00421 void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root)
00422 {
00423     const FactoryMap& map = factoryMap();
00424     
00425     FactoryMap::const_iterator i = map.begin();
00426     FactoryMap::const_iterator end = map.end();
00427     for (; i != end; ++i)
00428     {
00429                 LL_DEBUGS("AppInit") << "LLHTTPRegistrar::buildAllServices adding node for path "
00430                         << i->first << LL_ENDL;
00431                 
00432         root.addNode(i->first, i->second->build());
00433     }
00434 }
00435 
00436 LLPointer<LLSimpleResponse> LLSimpleResponse::create()
00437 {
00438         return new LLSimpleResponse();
00439 }
00440 
00441 LLSimpleResponse::~LLSimpleResponse()
00442 {
00443 }
00444 
00445 void LLSimpleResponse::result(const LLSD& result)
00446 {
00447         status(200, "OK");
00448 }
00449 
00450 void LLSimpleResponse::status(S32 code, const std::string& message)
00451 {
00452         mCode = code;
00453         mMessage = message;
00454 }
00455 
00456 void LLSimpleResponse::print(std::ostream& out) const
00457 {
00458         out << mCode << " " << mMessage;
00459 }
00460 
00461 
00462 std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp)
00463 {
00464         resp.print(out);
00465         return out;
00466 }

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