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
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
00100 LLSD LLHTTPNode::get() const
00101 {
00102 throw NotImplemented();
00103 }
00104
00105
00106 LLSD LLHTTPNode::put(const LLSD& input) const
00107 {
00108 throw NotImplemented();
00109 }
00110
00111
00112 LLSD LLHTTPNode::post(const LLSD& input) const
00113 {
00114 throw NotImplemented();
00115 }
00116
00117
00118
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
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
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
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
00172 LLSD LLHTTPNode::del(const LLSD&) const
00173 {
00174 throw NotImplemented();
00175 }
00176
00177
00178
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
00199 bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const
00200 {
00201 return remainder.size() == 0;
00202 }
00203
00204
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
00280
00281
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 }