HttpClientServerTest.C 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * Copyright (C) 2011 Emweb bvba, Kessel-Lo, Belgium.
  3. *
  4. * See the LICENSE file for terms of use.
  5. */
  6. #include <Wt/WConfig.h>
  7. #ifdef WT_THREADED
  8. #include <boost/test/unit_test.hpp>
  9. #include <boost/thread.hpp>
  10. #include <boost/thread/condition.hpp>
  11. #include <Wt/WResource>
  12. #include <Wt/WServer>
  13. #include <Wt/WIOService>
  14. #include <Wt/Http/Client>
  15. #include <Wt/Http/Response>
  16. #include <Wt/Http/ResponseContinuation>
  17. #include <Wt/Http/Request>
  18. using namespace Wt;
  19. namespace {
  20. class TestResource : public WResource
  21. {
  22. public:
  23. TestResource()
  24. : continuation_(false),
  25. delaySendingBody_(false),
  26. haveEverMoreData_(false),
  27. haveRandomMoreData_(false),
  28. aborted_(0)
  29. { }
  30. virtual ~TestResource() {
  31. beingDeleted();
  32. }
  33. void useContinuation() {
  34. continuation_ = true;
  35. }
  36. void delaySendingBody() {
  37. delaySendingBody_ = true;
  38. }
  39. void haveEverMoreData() {
  40. haveEverMoreData_ = true;
  41. }
  42. void haveRandomMoreData() {
  43. haveRandomMoreData_ = true;
  44. }
  45. int abortedCount() const {
  46. return aborted_;
  47. }
  48. virtual void handleRequest(const Http::Request& request,
  49. Http::Response& response)
  50. {
  51. if (continuation_)
  52. handleWithContinuation(request, response);
  53. else
  54. handleSimple(request, response);
  55. }
  56. virtual void handleAbort(const Http::Request& request)
  57. {
  58. ++aborted_;
  59. }
  60. private:
  61. bool continuation_;
  62. bool delaySendingBody_;
  63. bool haveEverMoreData_;
  64. bool haveRandomMoreData_;
  65. int aborted_;
  66. void handleSimple(const Http::Request& request,
  67. Http::Response& response)
  68. {
  69. response.setStatus(200);
  70. response.out() << "Hello";
  71. }
  72. void handleWithContinuation(const Http::Request& request,
  73. Http::Response& response)
  74. {
  75. if (request.continuation()) {
  76. response.out() << "Hello";
  77. if (haveEverMoreData_ ||
  78. (haveRandomMoreData_ && (rand() % 10 != 0)))
  79. response.createContinuation();
  80. } else {
  81. response.setStatus(200);
  82. Http::ResponseContinuation *c = response.createContinuation();
  83. if (delaySendingBody_)
  84. c->waitForMoreData();
  85. }
  86. }
  87. };
  88. class Server : public WServer
  89. {
  90. public:
  91. Server() {
  92. int argc = 7;
  93. const char *argv[]
  94. = { "test",
  95. "--http-address", "127.0.0.1",
  96. "--http-port", "0",
  97. "--docroot", "."
  98. };
  99. setServerConfiguration(argc, (char **)argv);
  100. addResource(&resource_, "/test");
  101. }
  102. std::string address()
  103. {
  104. return "127.0.0.1:" + boost::lexical_cast<std::string>(httpPort());
  105. }
  106. TestResource& resource() { return resource_; }
  107. private:
  108. TestResource resource_;
  109. };
  110. class Client : public Http::Client
  111. {
  112. public:
  113. Client()
  114. : done_(false),
  115. abortAfterHeaders_(false)
  116. {
  117. done().connect(this, &Client::onDone);
  118. headersReceived().connect(this, &Client::onHeadersReceived);
  119. bodyDataReceived().connect(this, &Client::onDataReceived);
  120. }
  121. void abortAfterHeaders()
  122. {
  123. abortAfterHeaders_ = true;
  124. }
  125. void waitDone()
  126. {
  127. boost::mutex::scoped_lock guard(doneMutex_);
  128. while (!done_)
  129. doneCondition_.wait(guard);
  130. }
  131. void reset()
  132. {
  133. done_ = false;
  134. }
  135. bool isDone()
  136. {
  137. return done_;
  138. }
  139. void onDone(boost::system::error_code err, const Http::Message& m)
  140. {
  141. boost::mutex::scoped_lock guard(doneMutex_);
  142. err_ = err;
  143. message_ = m;
  144. done_ = true;
  145. doneCondition_.notify_one();
  146. }
  147. void onHeadersReceived(const Http::Message& m)
  148. {
  149. if (abortAfterHeaders_)
  150. abort();
  151. }
  152. void onDataReceived(const std::string& d)
  153. {
  154. }
  155. boost::system::error_code err() { return err_; }
  156. const Http::Message& message() { return message_; }
  157. private:
  158. bool done_;
  159. bool abortAfterHeaders_;
  160. boost::condition doneCondition_;
  161. boost::mutex doneMutex_;
  162. boost::system::error_code err_;
  163. Http::Message message_;
  164. };
  165. }
  166. BOOST_AUTO_TEST_CASE( http_client_server_test1 )
  167. {
  168. Server server;
  169. if (server.start()) {
  170. Client client;
  171. client.get("http://" + server.address() + "/test");
  172. client.waitDone();
  173. BOOST_REQUIRE(!client.err());
  174. BOOST_REQUIRE(client.message().status() == 200);
  175. BOOST_REQUIRE(client.message().body() == "Hello");
  176. }
  177. }
  178. BOOST_AUTO_TEST_CASE( http_client_server_test2 )
  179. {
  180. Server server;
  181. server.resource().useContinuation();
  182. if (server.start()) {
  183. Client client;
  184. client.get("http://" + server.address() + "/test");
  185. client.waitDone();
  186. BOOST_REQUIRE(!client.err());
  187. BOOST_REQUIRE(client.message().status() == 200);
  188. BOOST_REQUIRE(client.message().body() == "Hello");
  189. }
  190. }
  191. BOOST_AUTO_TEST_CASE( http_client_server_test3 )
  192. {
  193. Server server;
  194. server.resource().useContinuation();
  195. server.resource().delaySendingBody();
  196. server.resource().haveEverMoreData();
  197. if (server.start()) {
  198. Client client;
  199. client.abortAfterHeaders();
  200. client.get("http://" + server.address() + "/test");
  201. client.waitDone();
  202. BOOST_REQUIRE(client.err() == boost::asio::error::bad_descriptor);
  203. }
  204. server.resource().haveMoreData();
  205. boost::this_thread::sleep(boost::posix_time::milliseconds(50));
  206. BOOST_REQUIRE(server.resource().abortedCount() == 1);
  207. }
  208. BOOST_AUTO_TEST_CASE( http_client_server_test4 )
  209. {
  210. Server server;
  211. server.resource().useContinuation();
  212. server.resource().delaySendingBody();
  213. server.resource().haveRandomMoreData();
  214. int abortedCount = 0;
  215. if (server.start()) {
  216. std::vector<Client *> clients;
  217. for (unsigned i = 0; i < 1000; ++i) {
  218. Client *client = new Client();
  219. client->get("http://" + server.address() + "/test");
  220. clients.push_back(client);
  221. }
  222. for (;;) {
  223. bool alldone = true;
  224. for (unsigned i = 0; i < clients.size(); ++i) {
  225. if (!clients[i]->isDone()) {
  226. if (i % 100 == 0) {
  227. clients[i]->abort();
  228. ++abortedCount;
  229. }
  230. alldone = false;
  231. break;
  232. }
  233. }
  234. if (!alldone)
  235. server.resource().haveMoreData();
  236. else
  237. break;
  238. }
  239. for (unsigned i = 0; i < 1000; ++i) {
  240. delete clients[i];
  241. }
  242. }
  243. }
  244. #endif // WT_THREADED