aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage/llhttpnode.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llhttpnode.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmessage/llhttpnode.cpp')
-rw-r--r--linden/indra/llmessage/llhttpnode.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llhttpnode.cpp b/linden/indra/llmessage/llhttpnode.cpp
new file mode 100644
index 0000000..e997415
--- /dev/null
+++ b/linden/indra/llmessage/llhttpnode.cpp
@@ -0,0 +1,468 @@
1/**
2 * @file llhttpnode.cpp
3 * @brief Implementation of classes for generic HTTP/LSL/REST handling.
4 *
5 * Copyright (c) 2006-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29#include "llhttpnode.h"
30
31#include "boost/tokenizer.hpp"
32
33#include "llstl.h"
34
35static const std::string CONTEXT_REQUEST("request");
36static const std::string CONTEXT_WILDCARD("wildcard");
37
38/**
39 * LLHTTPNode
40 */
41
42class LLHTTPNode::Impl
43{
44public:
45 typedef std::map<std::string, LLHTTPNode*> ChildMap;
46
47 ChildMap mNamedChildren;
48 LLHTTPNode* mWildcardChild;
49 std::string mWildcardName;
50 std::string mWildcardKey;
51 LLHTTPNode* mParentNode;
52
53 Impl() : mWildcardChild(NULL), mParentNode(NULL) { }
54
55 LLHTTPNode* findNamedChild(const std::string& name) const;
56};
57
58
59LLHTTPNode* LLHTTPNode::Impl::findNamedChild(const std::string& name) const
60{
61 LLHTTPNode* child = get_ptr_in_map(mNamedChildren, name);
62
63 if (!child && ((name[0] == '*') || (name == mWildcardName)))
64 {
65 child = mWildcardChild;
66 }
67
68 return child;
69}
70
71
72LLHTTPNode::LLHTTPNode()
73 : impl(* new Impl)
74{
75}
76
77// virtual
78LLHTTPNode::~LLHTTPNode()
79{
80 std::for_each(impl.mNamedChildren.begin(), impl.mNamedChildren.end(),
81 DeletePairedPointer());
82
83 delete impl.mWildcardChild;
84
85 delete &impl;
86}
87
88
89namespace {
90 class NotImplemented
91 {
92 };
93}
94
95// virtual
96LLSD LLHTTPNode::get() const
97{
98 throw NotImplemented();
99}
100
101// virtual
102LLSD LLHTTPNode::put(const LLSD& input) const
103{
104 throw NotImplemented();
105}
106
107// virtual
108LLSD LLHTTPNode::post(const LLSD& input) const
109{
110 throw NotImplemented();
111}
112
113
114// virtual
115void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const
116{
117 try
118 {
119 response->result(get());
120 }
121 catch (NotImplemented)
122 {
123 response->methodNotAllowed();
124 }
125}
126
127// virtual
128void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
129{
130 try
131 {
132 response->result(put(input));
133 }
134 catch (NotImplemented)
135 {
136 response->methodNotAllowed();
137 }
138}
139
140// virtual
141void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const
142{
143 try
144 {
145 response->result(post(input));
146 }
147 catch (NotImplemented)
148 {
149 response->methodNotAllowed();
150 }
151}
152
153// virtual
154void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const
155{
156 try
157 {
158 response->result(del(context));
159 }
160 catch (NotImplemented)
161 {
162 response->methodNotAllowed();
163 }
164
165}
166
167// virtual
168LLSD LLHTTPNode::del() const
169{
170 throw NotImplemented();
171}
172
173// virtual
174LLSD LLHTTPNode::del(const LLSD&) const
175{
176 return del();
177}
178
179
180// virtual
181LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const
182{
183 LLHTTPNode* namedChild = get_ptr_in_map(impl.mNamedChildren, name);
184 if (namedChild)
185 {
186 return namedChild;
187 }
188
189 if (impl.mWildcardChild
190 && impl.mWildcardChild->validate(name, context))
191 {
192 context[CONTEXT_REQUEST][CONTEXT_WILDCARD][impl.mWildcardKey] = name;
193 return impl.mWildcardChild;
194 }
195
196 return NULL;
197}
198
199
200// virtual
201bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const
202{
203 return remainder.size() == 0;
204}
205
206// virtual
207bool LLHTTPNode::validate(const std::string& name, LLSD& context) const
208{
209 return false;
210}
211
212const LLHTTPNode* LLHTTPNode::traverse(
213 const std::string& path, LLSD& context) const
214{
215 typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
216 boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
217 tokenizer tokens(path, sep);
218 tokenizer::iterator iter = tokens.begin();
219 tokenizer::iterator end = tokens.end();
220
221 const LLHTTPNode* node = this;
222 for(; iter != end; ++iter)
223 {
224 LLHTTPNode* child = node->getChild(*iter, context);
225 if(!child)
226 {
227 lldebugs << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << llendl;
228 break;
229 }
230 lldebugs << "LLHTTPNode::traverse: Found '" << *iter << "'" << llendl;
231
232 node = child;
233 }
234
235 LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
236 for(; iter != end; ++iter)
237 {
238 remainder.append(*iter);
239 }
240
241 return node->handles(remainder, context) ? node : NULL;
242}
243
244
245
246void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd)
247{
248 typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
249 boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
250 tokenizer tokens(path, sep);
251 tokenizer::iterator iter = tokens.begin();
252 tokenizer::iterator end = tokens.end();
253
254 LLHTTPNode* node = this;
255 for(; iter != end; ++iter)
256 {
257 LLHTTPNode* child = node->impl.findNamedChild(*iter);
258 if (!child) { break; }
259 node = child;
260 }
261
262 if (iter == end)
263 {
264 llwarns << "LLHTTPNode::addNode: already a node that handles "
265 << path << llendl;
266 return;
267 }
268
269 while (true)
270 {
271 std::string pathPart = *iter;
272
273 ++iter;
274 bool lastOne = iter == end;
275
276 LLHTTPNode* nextNode = lastOne ? nodeToAdd : new LLHTTPNode();
277
278 switch (pathPart[0])
279 {
280 case '<':
281 // *NOTE: This should really validate that it is of
282 // the proper form: <wildcardkey> so that the substr()
283 // generates the correct key name.
284 node->impl.mWildcardChild = nextNode;
285 node->impl.mWildcardName = pathPart;
286 if(node->impl.mWildcardKey.empty())
287 {
288 node->impl.mWildcardKey = pathPart.substr(
289 1,
290 pathPart.size() - 2);
291 }
292 break;
293 case '*':
294 node->impl.mWildcardChild = nextNode;
295 if(node->impl.mWildcardName.empty())
296 {
297 node->impl.mWildcardName = pathPart;
298 }
299 break;
300
301 default:
302 node->impl.mNamedChildren[pathPart] = nextNode;
303 }
304 nextNode->impl.mParentNode = node;
305
306 if (lastOne) break;
307 node = nextNode;
308 }
309}
310
311static void append_node_paths(LLSD& result,
312 const std::string& name, const LLHTTPNode* node)
313{
314 result.append(name);
315
316 LLSD paths = node->allNodePaths();
317 LLSD::array_const_iterator i = paths.beginArray();
318 LLSD::array_const_iterator end = paths.endArray();
319
320 for (; i != end; ++i)
321 {
322 result.append(name + "/" + (*i).asString());
323 }
324}
325
326LLSD LLHTTPNode::allNodePaths() const
327{
328 LLSD result;
329
330 Impl::ChildMap::const_iterator i = impl.mNamedChildren.begin();
331 Impl::ChildMap::const_iterator end = impl.mNamedChildren.end();
332 for (; i != end; ++i)
333 {
334 append_node_paths(result, i->first, i->second);
335 }
336
337 if (impl.mWildcardChild)
338 {
339 append_node_paths(result, impl.mWildcardName, impl.mWildcardChild);
340 }
341
342 return result;
343}
344
345
346const LLHTTPNode* LLHTTPNode::rootNode() const
347{
348 const LLHTTPNode* node = this;
349
350 while (true)
351 {
352 const LLHTTPNode* next = node->impl.mParentNode;
353 if (!next)
354 {
355 return node;
356 }
357 node = next;
358 }
359}
360
361
362const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const
363{
364 return impl.findNamedChild(name);
365}
366
367LLHTTPNode::Response::~Response()
368{
369}
370
371void LLHTTPNode::Response::status(S32 code)
372{
373 status(code, "Unknown Error");
374}
375
376void LLHTTPNode::Response::notFound(const std::string& message)
377{
378 status(404, message);
379}
380
381void LLHTTPNode::Response::notFound()
382{
383 status(404, "Not Found");
384}
385
386void LLHTTPNode::Response::methodNotAllowed()
387{
388 status(405, "Method Not Allowed");
389}
390
391void LLHTTPNode::describe(Description& desc) const
392{
393 desc.shortInfo("unknown service (missing describe() method)");
394}
395
396
397const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const
398{
399 return NULL;
400}
401
402
403
404namespace
405{
406 typedef std::map<std::string, LLHTTPRegistrar::NodeFactory*> FactoryMap;
407
408 FactoryMap& factoryMap()
409 {
410 static FactoryMap theMap;
411 return theMap;
412 }
413}
414
415LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
416
417void LLHTTPRegistrar::registerFactory(
418 const std::string& path, NodeFactory& factory)
419{
420 factoryMap()[path] = &factory;
421}
422
423void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root)
424{
425 const FactoryMap& map = factoryMap();
426
427 FactoryMap::const_iterator i = map.begin();
428 FactoryMap::const_iterator end = map.end();
429 for (; i != end; ++i)
430 {
431 llinfos << "LLHTTPRegistrar::buildAllServices adding node for path "
432 << i->first << llendl;
433
434 root.addNode(i->first, i->second->build());
435 }
436}
437
438LLPointer<LLSimpleResponse> LLSimpleResponse::create()
439{
440 return new LLSimpleResponse();
441}
442
443LLSimpleResponse::~LLSimpleResponse()
444{
445}
446
447void LLSimpleResponse::result(const LLSD& result)
448{
449 status(200, "OK");
450}
451
452void LLSimpleResponse::status(S32 code, const std::string& message)
453{
454 mCode = code;
455 mMessage = message;
456}
457
458void LLSimpleResponse::print(std::ostream& out) const
459{
460 out << mCode << " " << mMessage;
461}
462
463
464std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp)
465{
466 resp.print(out);
467 return out;
468}