PageRenderTime 33ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/test/lliohttpserver_tut.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 345 lines | 227 code | 62 blank | 56 comment | 7 complexity | f0812fa2b6a8476c1388836f5e24c652 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lliohttpserver_tut.cpp
  3. * @date May 2006
  4. * @brief HTTP server unit tests
  5. *
  6. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #include "linden_common.h"
  28. #include "lltut.h"
  29. #include "llbufferstream.h"
  30. #include "lliohttpserver.h"
  31. #include "llsdhttpserver.h"
  32. #include "llsdserialize.h"
  33. #include "llpipeutil.h"
  34. namespace tut
  35. {
  36. class HTTPServiceTestData
  37. {
  38. public:
  39. class DelayedEcho : public LLHTTPNode
  40. {
  41. HTTPServiceTestData* mTester;
  42. public:
  43. DelayedEcho(HTTPServiceTestData* tester) : mTester(tester) { }
  44. void post(ResponsePtr response, const LLSD& context, const LLSD& input) const
  45. {
  46. ensure("response already set", mTester->mResponse == ResponsePtr(NULL));
  47. mTester->mResponse = response;
  48. mTester->mResult = input;
  49. }
  50. };
  51. class WireHello : public LLIOPipe
  52. {
  53. protected:
  54. virtual EStatus process_impl(
  55. const LLChannelDescriptors& channels,
  56. buffer_ptr_t& buffer,
  57. bool& eos,
  58. LLSD& context,
  59. LLPumpIO* pump)
  60. {
  61. if(!eos) return STATUS_BREAK;
  62. LLSD sd = "yo!";
  63. LLBufferStream ostr(channels, buffer.get());
  64. ostr << LLSDXMLStreamer(sd);
  65. return STATUS_DONE;
  66. }
  67. };
  68. HTTPServiceTestData()
  69. : mResponse(NULL)
  70. {
  71. LLHTTPStandardServices::useServices();
  72. LLHTTPRegistrar::buildAllServices(mRoot);
  73. mRoot.addNode("/delayed/echo", new DelayedEcho(this));
  74. mRoot.addNode("/wire/hello", new LLHTTPNodeForPipe<WireHello>);
  75. }
  76. LLHTTPNode mRoot;
  77. LLHTTPNode::ResponsePtr mResponse;
  78. LLSD mResult;
  79. void pumpPipe(LLPumpIO* pump, S32 iterations)
  80. {
  81. while(iterations > 0)
  82. {
  83. pump->pump();
  84. pump->callback();
  85. --iterations;
  86. }
  87. }
  88. std::string makeRequest(
  89. const std::string& name,
  90. const std::string& httpRequest,
  91. bool timeout = false)
  92. {
  93. LLPipeStringInjector* injector = new LLPipeStringInjector(httpRequest);
  94. LLPipeStringExtractor* extractor = new LLPipeStringExtractor();
  95. apr_pool_t* pool;
  96. apr_pool_create(&pool, NULL);
  97. LLPumpIO* pump;
  98. pump = new LLPumpIO(pool);
  99. LLPumpIO::chain_t chain;
  100. LLSD context;
  101. chain.push_back(LLIOPipe::ptr_t(injector));
  102. LLIOHTTPServer::createPipe(chain, mRoot, LLSD());
  103. chain.push_back(LLIOPipe::ptr_t(extractor));
  104. pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS);
  105. pumpPipe(pump, 10);
  106. if(mResponse.notNull() && (! timeout))
  107. {
  108. mResponse->result(mResult);
  109. mResponse = NULL;
  110. }
  111. pumpPipe(pump, 10);
  112. std::string httpResult = extractor->string();
  113. chain.clear();
  114. delete pump;
  115. apr_pool_destroy(pool);
  116. if(mResponse.notNull() && timeout)
  117. {
  118. mResponse->result(mResult);
  119. mResponse = NULL;
  120. }
  121. return httpResult;
  122. }
  123. std::string httpGET(const std::string& uri,
  124. bool timeout = false)
  125. {
  126. std::string httpRequest = "GET " + uri + " HTTP/1.0\r\n\r\n";
  127. return makeRequest(uri, httpRequest, timeout);
  128. }
  129. std::string httpPOST(const std::string& uri,
  130. const std::string& body,
  131. bool timeout,
  132. const std::string& evilExtra = "")
  133. {
  134. std::ostringstream httpRequest;
  135. httpRequest << "POST " + uri + " HTTP/1.0\r\n";
  136. httpRequest << "Content-Length: " << body.size() << "\r\n";
  137. httpRequest << "\r\n";
  138. httpRequest << body;
  139. httpRequest << evilExtra;
  140. return makeRequest(uri, httpRequest.str(), timeout);
  141. }
  142. std::string httpPOST(const std::string& uri,
  143. const std::string& body,
  144. const std::string& evilExtra = "")
  145. {
  146. bool timeout = false;
  147. return httpPOST(uri, body, timeout, evilExtra);
  148. }
  149. };
  150. typedef test_group<HTTPServiceTestData> HTTPServiceTestGroup;
  151. typedef HTTPServiceTestGroup::object HTTPServiceTestObject;
  152. HTTPServiceTestGroup httpServiceTestGroup("http service");
  153. template<> template<>
  154. void HTTPServiceTestObject::test<1>()
  155. {
  156. std::string result = httpGET("web/hello");
  157. ensure_starts_with("web/hello status", result,
  158. "HTTP/1.0 200 OK\r\n");
  159. ensure_contains("web/hello content type", result,
  160. "Content-Type: application/llsd+xml\r\n");
  161. ensure_contains("web/hello content length", result,
  162. "Content-Length: 36\r\n");
  163. ensure_contains("web/hello content", result,
  164. "\r\n"
  165. "<llsd><string>hello</string></llsd>"
  166. );
  167. }
  168. template<> template<>
  169. void HTTPServiceTestObject::test<2>()
  170. {
  171. // test various HTTP errors
  172. std::string actual;
  173. actual = httpGET("web/missing");
  174. ensure_starts_with("web/missing 404", actual,
  175. "HTTP/1.0 404 Not Found\r\n");
  176. actual = httpGET("web/echo");
  177. ensure_starts_with("web/echo 405", actual,
  178. "HTTP/1.0 405 Method Not Allowed\r\n");
  179. }
  180. template<> template<>
  181. void HTTPServiceTestObject::test<3>()
  182. {
  183. // test POST & content-length handling
  184. std::string result;
  185. result = httpPOST("web/echo",
  186. "<llsd><integer>42</integer></llsd>");
  187. ensure_starts_with("web/echo status", result,
  188. "HTTP/1.0 200 OK\r\n");
  189. ensure_contains("web/echo content type", result,
  190. "Content-Type: application/llsd+xml\r\n");
  191. ensure_contains("web/echo content length", result,
  192. "Content-Length: 35\r\n");
  193. ensure_contains("web/hello content", result,
  194. "\r\n"
  195. "<llsd><integer>42</integer></llsd>"
  196. );
  197. /* TO DO: this test doesn't pass!!
  198. result = httpPOST("web/echo",
  199. "<llsd><string>evil</string></llsd>",
  200. "really! evil!!!");
  201. ensure_equals("web/echo evil result", result,
  202. "HTTP/1.0 200 OK\r\n"
  203. "Content-Length: 34\r\n"
  204. "\r\n"
  205. "<llsd><string>evil</string></llsd>"
  206. );
  207. */
  208. }
  209. template<> template<>
  210. void HTTPServiceTestObject::test<4>()
  211. {
  212. // test calling things based on pipes
  213. std::string result;
  214. result = httpGET("wire/hello");
  215. ensure_contains("wire/hello", result, "yo!");
  216. }
  217. template<> template<>
  218. void HTTPServiceTestObject::test<5>()
  219. {
  220. // test timeout before async response
  221. std::string result;
  222. bool timeout = true;
  223. result = httpPOST("delayed/echo",
  224. "<llsd><string>agent99</string></llsd>", timeout);
  225. ensure_equals("timeout delayed/echo status", result, std::string(""));
  226. }
  227. template<> template<>
  228. void HTTPServiceTestObject::test<6>()
  229. {
  230. // test delayed service
  231. std::string result;
  232. result = httpPOST("delayed/echo",
  233. "<llsd><string>agent99</string></llsd>");
  234. ensure_starts_with("delayed/echo status", result,
  235. "HTTP/1.0 200 OK\r\n");
  236. ensure_contains("delayed/echo content", result,
  237. "\r\n"
  238. "<llsd><string>agent99</string></llsd>"
  239. );
  240. }
  241. template<> template<>
  242. void HTTPServiceTestObject::test<7>()
  243. {
  244. // test large request
  245. std::stringstream stream;
  246. //U32 size = 36 * 1024 * 1024;
  247. //U32 size = 36 * 1024;
  248. //std::vector<char> data(size);
  249. //memset(&(data[0]), '1', size);
  250. //data[size - 1] = '\0';
  251. //std::string result = httpPOST("web/echo", &(data[0]));
  252. stream << "<llsd><array>";
  253. for(U32 i = 0; i < 1000000; ++i)
  254. {
  255. stream << "<integer>42</integer>";
  256. }
  257. stream << "</array></llsd>";
  258. llinfos << "HTTPServiceTestObject::test<7>"
  259. << stream.str().length() << llendl;
  260. std::string result = httpPOST("web/echo", stream.str());
  261. ensure_starts_with("large echo status", result, "HTTP/1.0 200 OK\r\n");
  262. }
  263. template<> template<>
  264. void HTTPServiceTestObject::test<8>()
  265. {
  266. // test the OPTIONS http method -- the default implementation
  267. // should return the X-Documentation-URL
  268. std::ostringstream http_request;
  269. http_request << "OPTIONS / HTTP/1.0\r\nHost: localhost\r\n\r\n";
  270. bool timeout = false;
  271. std::string result = makeRequest("/", http_request.str(), timeout);
  272. ensure_starts_with("OPTIONS verb ok", result, "HTTP/1.0 200 OK\r\n");
  273. ensure_contains(
  274. "Doc url header exists",
  275. result,
  276. "X-Documentation-URL: http://localhost");
  277. }
  278. /* TO DO:
  279. test generation of not found and method not allowed errors
  280. */
  281. }