test.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. #include <gtest/gtest.h>
  2. #include <httplib.h>
  3. #include <future>
  4. #include <iostream>
  5. #define SERVER_CERT_FILE "./cert.pem"
  6. #define SERVER_PRIVATE_KEY_FILE "./key.pem"
  7. #ifdef _WIN32
  8. #include <process.h>
  9. #define msleep(n) ::Sleep(n)
  10. #else
  11. #define msleep(n) ::usleep(n * 1000)
  12. #endif
  13. using namespace std;
  14. using namespace httplib;
  15. const char* HOST = "localhost";
  16. const int PORT = 1234;
  17. #ifdef _WIN32
  18. TEST(StartupTest, WSAStartup)
  19. {
  20. WSADATA wsaData;
  21. int ret = WSAStartup(0x0002, &wsaData);
  22. ASSERT_EQ(0, ret);
  23. }
  24. #endif
  25. TEST(SplitTest, ParseQueryString)
  26. {
  27. string s = "key1=val1&key2=val2&key3=val3";
  28. map<string, string> dic;
  29. detail::split(s.c_str(), s.c_str() + s.size(), '&', [&](const char* b, const char* e) {
  30. string key, val;
  31. detail::split(b, e, '=', [&](const char* b, const char* e) {
  32. if (key.empty()) {
  33. key.assign(b, e);
  34. } else {
  35. val.assign(b, e);
  36. }
  37. });
  38. dic[key] = val;
  39. });
  40. EXPECT_EQ("val1", dic["key1"]);
  41. EXPECT_EQ("val2", dic["key2"]);
  42. EXPECT_EQ("val3", dic["key3"]);
  43. }
  44. TEST(ParseQueryTest, ParseQueryString)
  45. {
  46. string s = "key1=val1&key2=val2&key3=val3";
  47. map<string, string> dic;
  48. detail::parse_query_text(s, dic);
  49. EXPECT_EQ("val1", dic["key1"]);
  50. EXPECT_EQ("val2", dic["key2"]);
  51. EXPECT_EQ("val3", dic["key3"]);
  52. }
  53. TEST(SocketTest, OpenClose)
  54. {
  55. socket_t sock = detail::create_server_socket(HOST, PORT, 0);
  56. ASSERT_NE(-1, sock);
  57. auto ret = detail::close_socket(sock);
  58. EXPECT_EQ(0, ret);
  59. }
  60. TEST(SocketTest, OpenCloseWithAI_PASSIVE)
  61. {
  62. socket_t sock = detail::create_server_socket(nullptr, PORT, AI_PASSIVE);
  63. ASSERT_NE(-1, sock);
  64. auto ret = detail::close_socket(sock);
  65. EXPECT_EQ(0, ret);
  66. }
  67. TEST(GetHeaderValueTest, DefaultValue)
  68. {
  69. MultiMap map = {{"Dummy","Dummy"}};
  70. auto val = detail::get_header_value(map, "Content-Type", "text/plain");
  71. ASSERT_STREQ("text/plain", val);
  72. }
  73. TEST(GetHeaderValueTest, DefaultValueInt)
  74. {
  75. MultiMap map = {{"Dummy","Dummy"}};
  76. auto val = detail::get_header_value_int(map, "Content-Length", 100);
  77. EXPECT_EQ(100, val);
  78. }
  79. TEST(GetHeaderValueTest, RegularValue)
  80. {
  81. MultiMap map = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
  82. auto val = detail::get_header_value(map, "Content-Type", "text/plain");
  83. ASSERT_STREQ("text/html", val);
  84. }
  85. TEST(GetHeaderValueTest, RegularValueInt)
  86. {
  87. MultiMap map = {{"Content-Length", "100"}, {"Dummy", "Dummy"}};
  88. auto val = detail::get_header_value_int(map, "Content-Length", 0);
  89. EXPECT_EQ(100, val);
  90. }
  91. class ServerTest : public ::testing::Test {
  92. protected:
  93. ServerTest()
  94. : cli_(HOST, PORT)
  95. #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  96. , svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
  97. #endif
  98. , up_(false) {}
  99. virtual void SetUp() {
  100. svr_.set_base_dir("./www");
  101. svr_.get("/hi", [&](const Request& req, Response& res) {
  102. res.set_content("Hello World!", "text/plain");
  103. });
  104. svr_.get("/", [&](const Request& req, Response& res) {
  105. res.set_redirect("/hi");
  106. });
  107. svr_.post("/person", [&](const Request& req, Response& res) {
  108. if (req.has_param("name") && req.has_param("note")) {
  109. persons_[req.params.at("name")] = req.params.at("note");
  110. } else {
  111. res.status = 400;
  112. }
  113. });
  114. svr_.get("/person/(.*)", [&](const Request& req, Response& res) {
  115. string name = req.matches[1];
  116. if (persons_.find(name) != persons_.end()) {
  117. auto note = persons_[name];
  118. res.set_content(note, "text/plain");
  119. } else {
  120. res.status = 404;
  121. }
  122. });
  123. svr_.get("/stop", [&](const Request& req, Response& res) {
  124. svr_.stop();
  125. });
  126. persons_["john"] = "programmer";
  127. f_ = async([&](){
  128. up_ = true;
  129. svr_.listen(HOST, PORT);
  130. });
  131. while (!up_) {
  132. msleep(1);
  133. }
  134. }
  135. virtual void TearDown() {
  136. //svr_.stop(); // NOTE: This causes dead lock on Windows.
  137. cli_.get("/stop");
  138. f_.get();
  139. }
  140. map<string, string> persons_;
  141. #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  142. SSLClient cli_;
  143. SSLServer svr_;
  144. #else
  145. Client cli_;
  146. Server svr_;
  147. #endif
  148. future<void> f_;
  149. bool up_;
  150. };
  151. TEST_F(ServerTest, GetMethod200)
  152. {
  153. auto res = cli_.get("/hi");
  154. ASSERT_TRUE(res != nullptr);
  155. EXPECT_EQ(200, res->status);
  156. EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
  157. EXPECT_EQ("Hello World!", res->body);
  158. }
  159. TEST_F(ServerTest, GetMethod302)
  160. {
  161. auto res = cli_.get("/");
  162. ASSERT_TRUE(res != nullptr);
  163. EXPECT_EQ(302, res->status);
  164. EXPECT_EQ("/hi", res->get_header_value("Location"));
  165. }
  166. TEST_F(ServerTest, GetMethod404)
  167. {
  168. auto res = cli_.get("/invalid");
  169. ASSERT_TRUE(res != nullptr);
  170. EXPECT_EQ(404, res->status);
  171. }
  172. TEST_F(ServerTest, HeadMethod200)
  173. {
  174. auto res = cli_.head("/hi");
  175. ASSERT_TRUE(res != nullptr);
  176. EXPECT_EQ(200, res->status);
  177. EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
  178. EXPECT_EQ("", res->body);
  179. }
  180. TEST_F(ServerTest, HeadMethod404)
  181. {
  182. auto res = cli_.head("/invalid");
  183. ASSERT_TRUE(res != nullptr);
  184. EXPECT_EQ(404, res->status);
  185. EXPECT_EQ("", res->body);
  186. }
  187. TEST_F(ServerTest, GetMethodPersonJohn)
  188. {
  189. auto res = cli_.get("/person/john");
  190. ASSERT_TRUE(res != nullptr);
  191. EXPECT_EQ(200, res->status);
  192. EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
  193. EXPECT_EQ("programmer", res->body);
  194. }
  195. TEST_F(ServerTest, PostMethod1)
  196. {
  197. auto res = cli_.get("/person/john1");
  198. ASSERT_TRUE(res != nullptr);
  199. ASSERT_EQ(404, res->status);
  200. res = cli_.post("/person", "name=john1&note=coder", "application/x-www-form-urlencoded");
  201. ASSERT_TRUE(res != nullptr);
  202. ASSERT_EQ(200, res->status);
  203. res = cli_.get("/person/john1");
  204. ASSERT_TRUE(res != nullptr);
  205. ASSERT_EQ(200, res->status);
  206. ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
  207. ASSERT_EQ("coder", res->body);
  208. }
  209. TEST_F(ServerTest, PostMethod2)
  210. {
  211. auto res = cli_.get("/person/john2");
  212. ASSERT_TRUE(res != nullptr);
  213. ASSERT_EQ(404, res->status);
  214. Map params;
  215. params["name"] = "john2";
  216. params["note"] = "coder";
  217. res = cli_.post("/person", params);
  218. ASSERT_TRUE(res != nullptr);
  219. ASSERT_EQ(200, res->status);
  220. res = cli_.get("/person/john2");
  221. ASSERT_TRUE(res != nullptr);
  222. ASSERT_EQ(200, res->status);
  223. ASSERT_EQ("text/plain", res->get_header_value("Content-Type"));
  224. ASSERT_EQ("coder", res->body);
  225. }
  226. TEST_F(ServerTest, GetMethodDir)
  227. {
  228. auto res = cli_.get("/dir/");
  229. ASSERT_TRUE(res != nullptr);
  230. EXPECT_EQ(200, res->status);
  231. EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
  232. auto body = R"(<html>
  233. <head>
  234. </head>
  235. <body>
  236. <a href="/dir/test.html">Test</a>
  237. <a href="/hi">hi</a>
  238. </body>
  239. </html>
  240. )";
  241. EXPECT_EQ(body, res->body);
  242. }
  243. TEST_F(ServerTest, GetMethodDirTest)
  244. {
  245. auto res = cli_.get("/dir/test.html");
  246. ASSERT_TRUE(res != nullptr);
  247. EXPECT_EQ(200, res->status);
  248. EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
  249. EXPECT_EQ("test.html", res->body);
  250. }
  251. TEST_F(ServerTest, InvalidBaseDir)
  252. {
  253. EXPECT_EQ(false, svr_.set_base_dir("invalid_dir"));
  254. EXPECT_EQ(true, svr_.set_base_dir("."));
  255. }
  256. class ServerTestWithAI_PASSIVE : public ::testing::Test {
  257. protected:
  258. ServerTestWithAI_PASSIVE()
  259. : cli_(HOST, PORT)
  260. #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  261. , svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
  262. #endif
  263. , up_(false) {}
  264. virtual void SetUp() {
  265. svr_.get("/hi", [&](const Request& req, Response& res) {
  266. res.set_content("Hello World!", "text/plain");
  267. });
  268. svr_.get("/stop", [&](const Request& req, Response& res) {
  269. svr_.stop();
  270. });
  271. f_ = async([&](){
  272. up_ = true;
  273. svr_.listen(nullptr, PORT, AI_PASSIVE);
  274. });
  275. while (!up_) {
  276. msleep(1);
  277. }
  278. }
  279. virtual void TearDown() {
  280. //svr_.stop(); // NOTE: This causes dead lock on Windows.
  281. cli_.get("/stop");
  282. f_.get();
  283. }
  284. #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  285. SSLClient cli_;
  286. SSLServer svr_;
  287. #else
  288. Client cli_;
  289. Server svr_;
  290. #endif
  291. future<void> f_;
  292. bool up_;
  293. };
  294. TEST_F(ServerTestWithAI_PASSIVE, GetMethod200)
  295. {
  296. auto res = cli_.get("/hi");
  297. ASSERT_TRUE(res != nullptr);
  298. EXPECT_EQ(200, res->status);
  299. EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
  300. EXPECT_EQ("Hello World!", res->body);
  301. }
  302. #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  303. TEST(SSLClientTest, ServerNameIndication)
  304. {
  305. SSLClient cli("httpbin.org", 443);
  306. auto res = cli.get("/get");
  307. ASSERT_TRUE(res != nullptr);
  308. ASSERT_EQ(200, res->status);
  309. }
  310. #endif
  311. #ifdef _WIN32
  312. TEST(CleanupTest, WSACleanup)
  313. {
  314. int ret = WSACleanup();
  315. ASSERT_EQ(0, ret);
  316. }
  317. #endif
  318. // vim: et ts=4 sw=4 cin cino={1s ff=unix