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
00173 {
00174         throw NotImplemented();
00175 }
00176 
00177 // virtual
00178 LLSD LLHTTPNode::del(const LLSD&) const
00179 {
00180         return del();
00181 }
00182 
00183 
00184 // virtual
00185 LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const
00186 {
00187         LLHTTPNode* namedChild = get_ptr_in_map(impl.mNamedChildren, name);
00188         if (namedChild)
00189         {
00190                 return namedChild;
00191         }
00192         
00193         if (impl.mWildcardChild
00194         &&  impl.mWildcardChild->validate(name, context))
00195         {
00196                 context[CONTEXT_REQUEST][CONTEXT_WILDCARD][impl.mWildcardKey] = name;
00197                 return impl.mWildcardChild;
00198         }
00199         
00200         return NULL;
00201 }
00202 
00203 
00204 // virtual
00205 bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const
00206 {
00207         return remainder.size() == 0;
00208 }
00209 
00210 // virtual
00211 bool LLHTTPNode::validate(const std::string& name, LLSD& context) const
00212 {
00213         return false;
00214 }
00215 
00216 const LLHTTPNode* LLHTTPNode::traverse(
00217         const std::string& path, LLSD& context) const
00218 {
00219         typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
00220         boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
00221         tokenizer tokens(path, sep);
00222         tokenizer::iterator iter = tokens.begin();
00223         tokenizer::iterator end = tokens.end();
00224 
00225         const LLHTTPNode* node = this;
00226         for(; iter != end; ++iter)
00227         {
00228                 LLHTTPNode* child = node->getChild(*iter, context);
00229                 if(!child) 
00230                 {
00231                         lldebugs << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << llendl;
00232                         break; 
00233                 }
00234                 lldebugs << "LLHTTPNode::traverse: Found '" << *iter << "'" << llendl;
00235 
00236                 node = child;
00237         }
00238 
00239         LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
00240         for(; iter != end; ++iter)
00241         {
00242                 remainder.append(*iter);
00243         }
00244 
00245         return node->handles(remainder, context) ? node : NULL;
00246 }
00247 
00248 
00249 
00250 void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd)
00251 {
00252         typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
00253         boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
00254         tokenizer tokens(path, sep);
00255         tokenizer::iterator iter = tokens.begin();
00256         tokenizer::iterator end = tokens.end();
00257 
00258         LLHTTPNode* node = this;
00259         for(; iter != end; ++iter)
00260         {
00261                 LLHTTPNode* child = node->impl.findNamedChild(*iter);
00262                 if (!child) { break; }
00263                 node = child;
00264         }
00265         
00266         if (iter == end)
00267         {
00268                 llwarns << "LLHTTPNode::addNode: already a node that handles "
00269                         << path << llendl;
00270                 return;
00271         }
00272         
00273         while (true)
00274         {
00275                 std::string pathPart = *iter;
00276                 
00277                 ++iter;
00278                 bool lastOne = iter == end;
00279                 
00280                 LLHTTPNode* nextNode = lastOne ? nodeToAdd : new LLHTTPNode();
00281                 
00282                 switch (pathPart[0])
00283                 {
00284                         case '<':
00285                                 // *NOTE: This should really validate that it is of
00286                                 // the proper form: <wildcardkey> so that the substr()
00287                                 // generates the correct key name.
00288                                 node->impl.mWildcardChild = nextNode;
00289                                 node->impl.mWildcardName = pathPart;
00290                                 if(node->impl.mWildcardKey.empty())
00291                                 {
00292                                         node->impl.mWildcardKey = pathPart.substr(
00293                                                 1,
00294                                                 pathPart.size() - 2);
00295                                 }
00296                                 break;
00297                         case '*':
00298                                 node->impl.mWildcardChild = nextNode;
00299                                 if(node->impl.mWildcardName.empty())
00300                                 {
00301                                         node->impl.mWildcardName = pathPart;
00302                                 }
00303                                 break;
00304                         
00305                         default:
00306                                 node->impl.mNamedChildren[pathPart] = nextNode;
00307                 }
00308                 nextNode->impl.mParentNode = node;
00309 
00310                 if (lastOne) break;
00311                 node = nextNode;
00312         }
00313 }
00314 
00315 static void append_node_paths(LLSD& result,
00316         const std::string& name, const LLHTTPNode* node)
00317 {
00318         result.append(name);
00319         
00320         LLSD paths = node->allNodePaths();
00321         LLSD::array_const_iterator i = paths.beginArray();
00322         LLSD::array_const_iterator end = paths.endArray();
00323         
00324         for (; i != end; ++i)
00325         {
00326                 result.append(name + "/" + (*i).asString());
00327         }
00328 }
00329 
00330 LLSD LLHTTPNode::allNodePaths() const
00331 {
00332         LLSD result;
00333         
00334         Impl::ChildMap::const_iterator i = impl.mNamedChildren.begin();
00335         Impl::ChildMap::const_iterator end = impl.mNamedChildren.end();
00336         for (; i != end; ++i)
00337         {
00338                 append_node_paths(result, i->first, i->second);
00339         }
00340         
00341         if (impl.mWildcardChild)
00342         {
00343                 append_node_paths(result, impl.mWildcardName, impl.mWildcardChild);
00344         }
00345         
00346         return result;
00347 }
00348 
00349 
00350 const LLHTTPNode* LLHTTPNode::rootNode() const
00351 {
00352         const LLHTTPNode* node = this;
00353         
00354         while (true)
00355         {
00356                 const LLHTTPNode* next = node->impl.mParentNode;
00357                 if (!next)
00358                 {
00359                         return node;
00360                 }
00361                 node = next;
00362         }
00363 }
00364 
00365 
00366 const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const
00367 {
00368         return impl.findNamedChild(name);
00369 }
00370 
00371 LLHTTPNode::Response::~Response()
00372 {
00373 }
00374 
00375 void LLHTTPNode::Response::status(S32 code)
00376 {
00377         status(code, "Unknown Error");
00378 }
00379 
00380 void LLHTTPNode::Response::notFound(const std::string& message)
00381 {
00382         status(404, message);
00383 }
00384 
00385 void LLHTTPNode::Response::notFound()
00386 {
00387         status(404, "Not Found");
00388 }
00389 
00390 void LLHTTPNode::Response::methodNotAllowed()
00391 {
00392         status(405, "Method Not Allowed");
00393 }
00394 
00395 void LLHTTPNode::describe(Description& desc) const
00396 {
00397         desc.shortInfo("unknown service (missing describe() method)");
00398 }
00399 
00400 
00401 const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const
00402 {
00403         return NULL;
00404 }
00405 
00406 
00407 
00408 namespace
00409 {
00410     typedef std::map<std::string, LLHTTPRegistrar::NodeFactory*>  FactoryMap;
00411     
00412     FactoryMap& factoryMap()
00413     {
00414         static FactoryMap theMap;
00415         return theMap;
00416     }
00417 }
00418 
00419 LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
00420 
00421 void LLHTTPRegistrar::registerFactory(
00422     const std::string& path, NodeFactory& factory)
00423 {
00424         factoryMap()[path] = &factory;
00425 }
00426 
00427 void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root)
00428 {
00429     const FactoryMap& map = factoryMap();
00430     
00431     FactoryMap::const_iterator i = map.begin();
00432     FactoryMap::const_iterator end = map.end();
00433     for (; i != end; ++i)
00434     {
00435                 llinfos << "LLHTTPRegistrar::buildAllServices adding node for path "
00436                         << i->first << llendl;
00437                 
00438         root.addNode(i->first, i->second->build());
00439     }
00440 }
00441 
00442 LLPointer<LLSimpleResponse> LLSimpleResponse::create()
00443 {
00444         return new LLSimpleResponse();
00445 }
00446 
00447 LLSimpleResponse::~LLSimpleResponse()
00448 {
00449 }
00450 
00451 void LLSimpleResponse::result(const LLSD& result)
00452 {
00453         status(200, "OK");
00454 }
00455 
00456 void LLSimpleResponse::status(S32 code, const std::string& message)
00457 {
00458         mCode = code;
00459         mMessage = message;
00460 }
00461 
00462 void LLSimpleResponse::print(std::ostream& out) const
00463 {
00464         out << mCode << " " << mMessage;
00465 }
00466 
00467 
00468 std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp)
00469 {
00470         resp.print(out);
00471         return out;
00472 }

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