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
00173 {
00174 throw NotImplemented();
00175 }
00176
00177
00178 LLSD LLHTTPNode::del(const LLSD&) const
00179 {
00180 return del();
00181 }
00182
00183
00184
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
00205 bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const
00206 {
00207 return remainder.size() == 0;
00208 }
00209
00210
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
00286
00287
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 }