diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llhttpnode.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 468 |
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 | |||
35 | static const std::string CONTEXT_REQUEST("request"); | ||
36 | static const std::string CONTEXT_WILDCARD("wildcard"); | ||
37 | |||
38 | /** | ||
39 | * LLHTTPNode | ||
40 | */ | ||
41 | |||
42 | class LLHTTPNode::Impl | ||
43 | { | ||
44 | public: | ||
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 | |||
59 | LLHTTPNode* 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 | |||
72 | LLHTTPNode::LLHTTPNode() | ||
73 | : impl(* new Impl) | ||
74 | { | ||
75 | } | ||
76 | |||
77 | // virtual | ||
78 | LLHTTPNode::~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 | |||
89 | namespace { | ||
90 | class NotImplemented | ||
91 | { | ||
92 | }; | ||
93 | } | ||
94 | |||
95 | // virtual | ||
96 | LLSD LLHTTPNode::get() const | ||
97 | { | ||
98 | throw NotImplemented(); | ||
99 | } | ||
100 | |||
101 | // virtual | ||
102 | LLSD LLHTTPNode::put(const LLSD& input) const | ||
103 | { | ||
104 | throw NotImplemented(); | ||
105 | } | ||
106 | |||
107 | // virtual | ||
108 | LLSD LLHTTPNode::post(const LLSD& input) const | ||
109 | { | ||
110 | throw NotImplemented(); | ||
111 | } | ||
112 | |||
113 | |||
114 | // virtual | ||
115 | void 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 | ||
128 | void 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 | ||
141 | void 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 | ||
154 | void 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 | ||
168 | LLSD LLHTTPNode::del() const | ||
169 | { | ||
170 | throw NotImplemented(); | ||
171 | } | ||
172 | |||
173 | // virtual | ||
174 | LLSD LLHTTPNode::del(const LLSD&) const | ||
175 | { | ||
176 | return del(); | ||
177 | } | ||
178 | |||
179 | |||
180 | // virtual | ||
181 | LLHTTPNode* 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 | ||
201 | bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const | ||
202 | { | ||
203 | return remainder.size() == 0; | ||
204 | } | ||
205 | |||
206 | // virtual | ||
207 | bool LLHTTPNode::validate(const std::string& name, LLSD& context) const | ||
208 | { | ||
209 | return false; | ||
210 | } | ||
211 | |||
212 | const 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 | |||
246 | void 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 | |||
311 | static 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 | |||
326 | LLSD 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 | |||
346 | const 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 | |||
362 | const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const | ||
363 | { | ||
364 | return impl.findNamedChild(name); | ||
365 | } | ||
366 | |||
367 | LLHTTPNode::Response::~Response() | ||
368 | { | ||
369 | } | ||
370 | |||
371 | void LLHTTPNode::Response::status(S32 code) | ||
372 | { | ||
373 | status(code, "Unknown Error"); | ||
374 | } | ||
375 | |||
376 | void LLHTTPNode::Response::notFound(const std::string& message) | ||
377 | { | ||
378 | status(404, message); | ||
379 | } | ||
380 | |||
381 | void LLHTTPNode::Response::notFound() | ||
382 | { | ||
383 | status(404, "Not Found"); | ||
384 | } | ||
385 | |||
386 | void LLHTTPNode::Response::methodNotAllowed() | ||
387 | { | ||
388 | status(405, "Method Not Allowed"); | ||
389 | } | ||
390 | |||
391 | void LLHTTPNode::describe(Description& desc) const | ||
392 | { | ||
393 | desc.shortInfo("unknown service (missing describe() method)"); | ||
394 | } | ||
395 | |||
396 | |||
397 | const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const | ||
398 | { | ||
399 | return NULL; | ||
400 | } | ||
401 | |||
402 | |||
403 | |||
404 | namespace | ||
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 | |||
415 | LLHTTPRegistrar::NodeFactory::~NodeFactory() { } | ||
416 | |||
417 | void LLHTTPRegistrar::registerFactory( | ||
418 | const std::string& path, NodeFactory& factory) | ||
419 | { | ||
420 | factoryMap()[path] = &factory; | ||
421 | } | ||
422 | |||
423 | void 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 | |||
438 | LLPointer<LLSimpleResponse> LLSimpleResponse::create() | ||
439 | { | ||
440 | return new LLSimpleResponse(); | ||
441 | } | ||
442 | |||
443 | LLSimpleResponse::~LLSimpleResponse() | ||
444 | { | ||
445 | } | ||
446 | |||
447 | void LLSimpleResponse::result(const LLSD& result) | ||
448 | { | ||
449 | status(200, "OK"); | ||
450 | } | ||
451 | |||
452 | void LLSimpleResponse::status(S32 code, const std::string& message) | ||
453 | { | ||
454 | mCode = code; | ||
455 | mMessage = message; | ||
456 | } | ||
457 | |||
458 | void LLSimpleResponse::print(std::ostream& out) const | ||
459 | { | ||
460 | out << mCode << " " << mMessage; | ||
461 | } | ||
462 | |||
463 | |||
464 | std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp) | ||
465 | { | ||
466 | resp.print(out); | ||
467 | return out; | ||
468 | } | ||