llhttpnode_tut.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:12k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lliohttpnode_tut.cpp
  3.  * @date   May 2006
  4.  * @brief HTTP server unit tests
  5.  *
  6.  * $LicenseInfo:firstyear=2006&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2006-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  */
  33. #include "linden_common.h"
  34. #include "lltut.h"
  35. #include "llhttpnode.h"
  36. #include "llsdhttpserver.h"
  37. namespace tut
  38. {
  39. struct HTTPNodeTestData
  40. {
  41. LLHTTPNode mRoot;
  42. LLSD mContext;
  43. const LLSD& context() { return mContext; }
  44. std::string remainderPath()
  45. {
  46. std::ostringstream pathOutput;
  47. bool addSlash = false;
  48. LLSD& remainder = mContext["request"]["remainder"];
  49. for (LLSD::array_const_iterator i = remainder.beginArray();
  50. i != remainder.endArray();
  51. ++i)
  52. {
  53. if (addSlash) { pathOutput << '/'; }
  54. pathOutput << i->asString();
  55. addSlash = true;
  56. }
  57. return pathOutput.str();
  58. }
  59. void ensureRootTraversal(const std::string& path,
  60. const LLHTTPNode* expectedNode,
  61. const char* expectedRemainder)
  62. {
  63. mContext.clear();
  64. const LLHTTPNode* actualNode = mRoot.traverse(path, mContext);
  65. ensure_equals("traverse " + path + " node",
  66. actualNode, expectedNode);
  67. ensure_equals("traverse " + path + " remainder",
  68. remainderPath(), expectedRemainder);
  69. }
  70. class Response : public LLHTTPNode::Response
  71. {
  72. public:
  73. static LLPointer<Response> create() {return new Response();}
  74. LLSD mResult;
  75. void result(const LLSD& result) { mResult = result; }
  76. void status(S32 code, const std::string& message) { }
  77. void extendedResult(S32 code, const std::string& message, const LLSD& headers) { }
  78. private:
  79. Response() {;} // Must be accessed through LLPointer.
  80. };
  81. typedef LLPointer<Response> ResponsePtr;
  82. LLSD get(const std::string& path)
  83. {
  84. mContext.clear();
  85. const LLHTTPNode* node = mRoot.traverse(path, mContext);
  86. ensure(path + " found", node != NULL);
  87. ResponsePtr response = Response::create();
  88. node->get(LLHTTPNode::ResponsePtr(response), mContext);
  89. return response->mResult;
  90. }
  91. LLSD post(const std::string& path, const LLSD& input)
  92. {
  93. mContext.clear();
  94. const LLHTTPNode* node = mRoot.traverse(path, mContext);
  95. ensure(path + " found", node != NULL);
  96. ResponsePtr response = Response::create();
  97. node->post(LLHTTPNode::ResponsePtr(response), mContext, input);
  98. return response->mResult;
  99. }
  100. void ensureMemberString(const std::string& name,
  101. const LLSD& actualMap, const std::string& member,
  102. const std::string& expectedValue)
  103. {
  104. ensure_equals(name + " " + member,
  105. actualMap[member].asString(), expectedValue);
  106. }
  107. void ensureInArray(const LLSD& actualArray,
  108. const std::string& expectedValue)
  109. {
  110. LLSD::array_const_iterator i = actualArray.beginArray();
  111. LLSD::array_const_iterator end = actualArray.endArray();
  112. for (; i != end; ++i)
  113. {
  114. std::string path = i->asString();
  115. if (path == expectedValue)
  116. {
  117. return;
  118. }
  119. }
  120. fail("didn't find " + expectedValue);
  121. }
  122. };
  123. typedef test_group<HTTPNodeTestData> HTTPNodeTestGroup;
  124. typedef HTTPNodeTestGroup::object HTTPNodeTestObject;
  125. HTTPNodeTestGroup httpNodeTestGroup("http node");
  126. template<> template<>
  127. void HTTPNodeTestObject::test<1>()
  128. {
  129. // traversal of the lone node
  130. ensureRootTraversal("", &mRoot, "");
  131. ensureRootTraversal("/", &mRoot, "");
  132. ensureRootTraversal("foo", NULL, "foo");
  133. ensureRootTraversal("foo/bar", NULL, "foo/bar");
  134. ensure_equals("root of root", mRoot.rootNode(), &mRoot);
  135. }
  136. template<> template<>
  137. void HTTPNodeTestObject::test<2>()
  138. {
  139. // simple traversal of a single node
  140. LLHTTPNode* helloNode = new LLHTTPNode;
  141. mRoot.addNode("hello", helloNode);
  142. ensureRootTraversal("hello", helloNode, "");
  143. ensureRootTraversal("/hello", helloNode, "");
  144. ensureRootTraversal("hello/", helloNode, "");
  145. ensureRootTraversal("/hello/", helloNode, "");
  146. ensureRootTraversal("hello/there", NULL, "there");
  147. ensure_equals("root of hello", helloNode->rootNode(), &mRoot);
  148. }
  149. template<> template<>
  150. void HTTPNodeTestObject::test<3>()
  151. {
  152. // traversal of mutli-branched tree
  153. LLHTTPNode* greekNode = new LLHTTPNode;
  154. LLHTTPNode* alphaNode = new LLHTTPNode;
  155. LLHTTPNode* betaNode = new LLHTTPNode;
  156. LLHTTPNode* gammaNode = new LLHTTPNode;
  157. greekNode->addNode("alpha", alphaNode);
  158. greekNode->addNode("beta", betaNode);
  159. greekNode->addNode("gamma", gammaNode);
  160. mRoot.addNode("greek", greekNode);
  161. LLHTTPNode* hebrewNode = new LLHTTPNode;
  162. LLHTTPNode* alephNode = new LLHTTPNode;
  163. hebrewNode->addNode("aleph", alephNode);
  164. mRoot.addNode("hebrew", hebrewNode);
  165. ensureRootTraversal("greek/alpha", alphaNode, "");
  166. ensureRootTraversal("greek/beta", betaNode, "");
  167. ensureRootTraversal("greek/delta", NULL, "delta");
  168. ensureRootTraversal("greek/gamma", gammaNode, "");
  169. ensureRootTraversal("hebrew/aleph", alephNode, "");
  170. ensure_equals("root of greek", greekNode->rootNode(), &mRoot);
  171. ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot);
  172. ensure_equals("root of beta", betaNode->rootNode(), &mRoot);
  173. ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot);
  174. ensure_equals("root of hebrew", hebrewNode->rootNode(), &mRoot);
  175. ensure_equals("root of aleph", alephNode->rootNode(), &mRoot);
  176. }
  177. template<> template<>
  178. void HTTPNodeTestObject::test<4>()
  179. {
  180. // automatic creation of parent nodes and not overriding existing nodes
  181. LLHTTPNode* alphaNode = new LLHTTPNode;
  182. LLHTTPNode* betaNode = new LLHTTPNode;
  183. LLHTTPNode* gammaNode = new LLHTTPNode;
  184. LLHTTPNode* gamma2Node = new LLHTTPNode;
  185. mRoot.addNode("greek/alpha", alphaNode);
  186. mRoot.addNode("greek/beta", betaNode);
  187. mRoot.addNode("greek/gamma", gammaNode);
  188. mRoot.addNode("greek/gamma", gamma2Node);
  189. LLHTTPNode* alephNode = new LLHTTPNode;
  190. mRoot.addNode("hebrew/aleph", alephNode);
  191. ensureRootTraversal("greek/alpha", alphaNode, "");
  192. ensureRootTraversal("greek/beta", betaNode, "");
  193. ensureRootTraversal("greek/delta", NULL, "delta");
  194. ensureRootTraversal("greek/gamma", gammaNode, "");
  195. ensureRootTraversal("hebrew/aleph", alephNode, "");
  196. ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot);
  197. ensure_equals("root of beta", betaNode->rootNode(), &mRoot);
  198. ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot);
  199. ensure_equals("root of aleph", alephNode->rootNode(), &mRoot);
  200. }
  201. class IntegerNode : public LLHTTPNode
  202. {
  203. public:
  204. virtual void get(ResponsePtr response, const LLSD& context) const
  205. {
  206. int n = context["extra"]["value"];
  207. LLSD info;
  208. info["value"] = n;
  209. info["positive"] = n > 0;
  210. info["zero"] = n == 0;
  211. info["negative"] = n < 0;
  212. response->result(info);
  213. }
  214. virtual bool validate(const std::string& name, LLSD& context) const
  215. {
  216. int n;
  217. std::istringstream i_stream(name);
  218. i_stream >> n;
  219. if (i_stream.fail()  ||  i_stream.get() != EOF)
  220. {
  221. return false;
  222. }
  223. context["extra"]["value"] = n;
  224. return true;
  225. }
  226. };
  227. class SquareNode : public LLHTTPNode
  228. {
  229. public:
  230. virtual void get(ResponsePtr response, const LLSD& context) const
  231. {
  232. int n = context["extra"]["value"];
  233. response->result(n*n);
  234. }
  235. };
  236. template<> template<>
  237. void HTTPNodeTestObject::test<5>()
  238. {
  239. // wildcard nodes
  240. LLHTTPNode* miscNode = new LLHTTPNode;
  241. LLHTTPNode* iNode = new IntegerNode;
  242. LLHTTPNode* sqNode = new SquareNode;
  243. mRoot.addNode("test/misc", miscNode);
  244. mRoot.addNode("test/<int>", iNode);
  245. mRoot.addNode("test/<int>/square", sqNode);
  246. ensureRootTraversal("test/42", iNode, "");
  247. ensure_equals("stored integer",
  248. context()["extra"]["value"].asInteger(), 42);
  249. ensureRootTraversal("test/bob", NULL, "bob");
  250. ensure("nothing stored",
  251. context()["extra"]["value"].isUndefined());
  252. ensureRootTraversal("test/3/square", sqNode, "");
  253. ResponsePtr response = Response::create();
  254. sqNode->get(LLHTTPNode::ResponsePtr(response), context());
  255. ensure_equals("square result", response->mResult.asInteger(), 9);
  256. }
  257. class AlphaNode : public LLHTTPNode
  258. {
  259. public:
  260. virtual bool handles(const LLSD& remainder, LLSD& context) const
  261. {
  262. LLSD::array_const_iterator i = remainder.beginArray();
  263. LLSD::array_const_iterator end = remainder.endArray();
  264. for (; i != end; ++i)
  265. {
  266. std::string s = i->asString();
  267. if (s.empty() || s[0] != 'a')
  268. {
  269. return false;
  270. }
  271. }
  272. return true;
  273. }
  274. };
  275. template<> template<>
  276. void HTTPNodeTestObject::test<6>()
  277. {
  278. // nodes that handle remainders
  279. LLHTTPNode* miscNode = new LLHTTPNode;
  280. LLHTTPNode* aNode = new AlphaNode;
  281. LLHTTPNode* zNode = new LLHTTPNode;
  282. mRoot.addNode("test/misc", miscNode);
  283. mRoot.addNode("test/alpha", aNode);
  284. mRoot.addNode("test/alpha/zebra", zNode);
  285. ensureRootTraversal("test/alpha", aNode, "");
  286. ensureRootTraversal("test/alpha/abe", aNode, "abe");
  287. ensureRootTraversal("test/alpha/abe/amy", aNode, "abe/amy");
  288. ensureRootTraversal("test/alpha/abe/bea", NULL, "abe/bea");
  289. ensureRootTraversal("test/alpha/bob", NULL, "bob");
  290. ensureRootTraversal("test/alpha/zebra", zNode, "");
  291. }
  292. template<> template<>
  293. void HTTPNodeTestObject::test<7>()
  294. {
  295. // test auto registration
  296. LLHTTPStandardServices::useServices();
  297. LLHTTPRegistrar::buildAllServices(mRoot);
  298. {
  299. LLSD result = get("web/hello");
  300. ensure_equals("hello result", result.asString(), "hello");
  301. }
  302. {
  303. LLSD stuff = 3.14159;
  304. LLSD result = post("web/echo", stuff);
  305. ensure_equals("echo result", result, stuff);
  306. }
  307. }
  308. template<> template<>
  309. void HTTPNodeTestObject::test<8>()
  310. {
  311. // test introspection
  312. LLHTTPRegistrar::buildAllServices(mRoot);
  313. mRoot.addNode("test/misc", new LLHTTPNode);
  314. mRoot.addNode("test/<int>", new IntegerNode);
  315. mRoot.addNode("test/<int>/square", new SquareNode);
  316. const LLSD result = get("web/server/api");
  317. ensure("result is array", result.isArray());
  318. ensure("result size", result.size() >= 2);
  319. ensureInArray(result, "web/echo");
  320. ensureInArray(result, "web/hello");
  321. ensureInArray(result, "test/misc");
  322. ensureInArray(result, "test/<int>");
  323. ensureInArray(result, "test/<int>/square");
  324. }
  325. template<> template<>
  326. void HTTPNodeTestObject::test<9>()
  327. {
  328. // test introspection details
  329. LLHTTPRegistrar::buildAllServices(mRoot);
  330. const LLSD helloDetails = get("web/server/api/web/hello");
  331. ensure_contains("hello description",
  332. helloDetails["description"].asString(), "hello");
  333. ensure_equals("method name", helloDetails["api"][0].asString(), std::string("GET"));
  334. ensureMemberString("hello", helloDetails, "output", ""hello"");
  335. ensure_contains("hello __file__",
  336. helloDetails["__file__"].asString(), "llsdhttpserver.cpp");
  337. ensure("hello line", helloDetails["__line__"].isInteger());
  338. const LLSD echoDetails = get("web/server/api/web/echo");
  339. ensure_contains("echo description",
  340. echoDetails["description"].asString(), "echo");
  341. ensure_equals("method name", echoDetails["api"][0].asString(), std::string("POST"));
  342. ensureMemberString("echo", echoDetails, "input", "<any>");
  343. ensureMemberString("echo", echoDetails, "output", "<the input>");
  344. ensure_contains("echo __file__",
  345. echoDetails["__file__"].asString(), "llsdhttpserver.cpp");
  346. ensure("echo", echoDetails["__line__"].isInteger());
  347. }
  348. }