PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/testcurl/test_get_sendfile.c

https://gitlab.com/karlson2k/libmicrohttpd-old
C | 514 lines | 436 code | 39 blank | 39 comment | 97 complexity | e2e823e7de257e27e3147ddbc71961a9 MD5 | raw file
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2007, 2009 Christian Grothoff
  4. libmicrohttpd is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 2, or (at your
  7. option) any later version.
  8. libmicrohttpd is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with libmicrohttpd; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. /**
  18. * @file test_get_sendfile.c
  19. * @brief Testcase for libmicrohttpd response from FD
  20. * @author Christian Grothoff
  21. */
  22. #include "MHD_config.h"
  23. #include "platform.h"
  24. #include <curl/curl.h>
  25. #include <microhttpd.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <time.h>
  29. #include <sys/types.h>
  30. #include <fcntl.h>
  31. #include "mhd_sockets.h"
  32. #ifndef WINDOWS
  33. #include <sys/socket.h>
  34. #include <unistd.h>
  35. #endif
  36. #if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
  37. #undef CPU_COUNT
  38. #endif
  39. #if !defined(CPU_COUNT)
  40. #define CPU_COUNT 2
  41. #endif
  42. #define TESTSTR "This is the content of the test file we are sending using sendfile (if available)"
  43. static char *sourcefile;
  44. static int oneone;
  45. struct CBC
  46. {
  47. char *buf;
  48. size_t pos;
  49. size_t size;
  50. };
  51. static size_t
  52. copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
  53. {
  54. struct CBC *cbc = ctx;
  55. if (cbc->pos + size * nmemb > cbc->size)
  56. return 0; /* overflow */
  57. memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
  58. cbc->pos += size * nmemb;
  59. return size * nmemb;
  60. }
  61. static int
  62. ahc_echo (void *cls,
  63. struct MHD_Connection *connection,
  64. const char *url,
  65. const char *method,
  66. const char *version,
  67. const char *upload_data, size_t *upload_data_size,
  68. void **unused)
  69. {
  70. static int ptr;
  71. const char *me = cls;
  72. struct MHD_Response *response;
  73. int ret;
  74. int fd;
  75. if (0 != strcmp (me, method))
  76. return MHD_NO; /* unexpected method */
  77. if (&ptr != *unused)
  78. {
  79. *unused = &ptr;
  80. return MHD_YES;
  81. }
  82. *unused = NULL;
  83. fd = open (sourcefile, O_RDONLY);
  84. if (fd == -1)
  85. {
  86. fprintf (stderr, "Failed to open `%s': %s\n",
  87. sourcefile,
  88. strerror (errno));
  89. exit (1);
  90. }
  91. response = MHD_create_response_from_fd (strlen (TESTSTR), fd);
  92. ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  93. MHD_destroy_response (response);
  94. if (ret == MHD_NO)
  95. abort ();
  96. return ret;
  97. }
  98. static int
  99. testInternalGet ()
  100. {
  101. struct MHD_Daemon *d;
  102. CURL *c;
  103. char buf[2048];
  104. struct CBC cbc;
  105. CURLcode errornum;
  106. cbc.buf = buf;
  107. cbc.size = 2048;
  108. cbc.pos = 0;
  109. d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
  110. 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
  111. if (d == NULL)
  112. return 1;
  113. c = curl_easy_init ();
  114. curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/");
  115. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  116. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  117. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  118. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  119. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  120. if (oneone)
  121. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  122. else
  123. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  124. /* NOTE: use of CONNECTTIMEOUT without also
  125. setting NOSIGNAL results in really weird
  126. crashes on my system!*/
  127. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  128. if (CURLE_OK != (errornum = curl_easy_perform (c)))
  129. {
  130. fprintf (stderr,
  131. "curl_easy_perform failed: `%s'\n",
  132. curl_easy_strerror (errornum));
  133. curl_easy_cleanup (c);
  134. MHD_stop_daemon (d);
  135. return 2;
  136. }
  137. curl_easy_cleanup (c);
  138. MHD_stop_daemon (d);
  139. if (cbc.pos != strlen (TESTSTR))
  140. return 4;
  141. if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
  142. return 8;
  143. return 0;
  144. }
  145. static int
  146. testMultithreadedGet ()
  147. {
  148. struct MHD_Daemon *d;
  149. CURL *c;
  150. char buf[2048];
  151. struct CBC cbc;
  152. CURLcode errornum;
  153. cbc.buf = buf;
  154. cbc.size = 2048;
  155. cbc.pos = 0;
  156. d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
  157. 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
  158. if (d == NULL)
  159. return 16;
  160. c = curl_easy_init ();
  161. curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/");
  162. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  163. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  164. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  165. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  166. if (oneone)
  167. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  168. else
  169. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  170. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  171. /* NOTE: use of CONNECTTIMEOUT without also
  172. setting NOSIGNAL results in really weird
  173. crashes on my system! */
  174. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  175. if (CURLE_OK != (errornum = curl_easy_perform (c)))
  176. {
  177. fprintf (stderr,
  178. "curl_easy_perform failed: `%s'\n",
  179. curl_easy_strerror (errornum));
  180. curl_easy_cleanup (c);
  181. MHD_stop_daemon (d);
  182. return 32;
  183. }
  184. curl_easy_cleanup (c);
  185. MHD_stop_daemon (d);
  186. if (cbc.pos != strlen (TESTSTR))
  187. return 64;
  188. if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
  189. return 128;
  190. return 0;
  191. }
  192. static int
  193. testMultithreadedPoolGet ()
  194. {
  195. struct MHD_Daemon *d;
  196. CURL *c;
  197. char buf[2048];
  198. struct CBC cbc;
  199. CURLcode errornum;
  200. cbc.buf = buf;
  201. cbc.size = 2048;
  202. cbc.pos = 0;
  203. d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
  204. 1081, NULL, NULL, &ahc_echo, "GET",
  205. MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END);
  206. if (d == NULL)
  207. return 16;
  208. c = curl_easy_init ();
  209. curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/");
  210. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  211. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  212. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  213. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  214. if (oneone)
  215. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  216. else
  217. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  218. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  219. /* NOTE: use of CONNECTTIMEOUT without also
  220. setting NOSIGNAL results in really weird
  221. crashes on my system!*/
  222. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  223. if (CURLE_OK != (errornum = curl_easy_perform (c)))
  224. {
  225. fprintf (stderr,
  226. "curl_easy_perform failed: `%s'\n",
  227. curl_easy_strerror (errornum));
  228. curl_easy_cleanup (c);
  229. MHD_stop_daemon (d);
  230. return 32;
  231. }
  232. curl_easy_cleanup (c);
  233. MHD_stop_daemon (d);
  234. if (cbc.pos != strlen (TESTSTR))
  235. return 64;
  236. if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
  237. return 128;
  238. return 0;
  239. }
  240. static int
  241. testExternalGet ()
  242. {
  243. struct MHD_Daemon *d;
  244. CURL *c;
  245. char buf[2048];
  246. struct CBC cbc;
  247. CURLM *multi;
  248. CURLMcode mret;
  249. fd_set rs;
  250. fd_set ws;
  251. fd_set es;
  252. MHD_socket maxsock;
  253. #ifdef MHD_WINSOCK_SOCKETS
  254. int maxposixs; /* Max socket number unused on W32 */
  255. #else /* MHD_POSIX_SOCKETS */
  256. #define maxposixs maxsock
  257. #endif /* MHD_POSIX_SOCKETS */
  258. int running;
  259. struct CURLMsg *msg;
  260. time_t start;
  261. struct timeval tv;
  262. multi = NULL;
  263. cbc.buf = buf;
  264. cbc.size = 2048;
  265. cbc.pos = 0;
  266. d = MHD_start_daemon (MHD_USE_DEBUG,
  267. 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
  268. if (d == NULL)
  269. return 256;
  270. c = curl_easy_init ();
  271. curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/");
  272. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  273. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  274. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  275. if (oneone)
  276. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  277. else
  278. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  279. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  280. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  281. /* NOTE: use of CONNECTTIMEOUT without also
  282. setting NOSIGNAL results in really weird
  283. crashes on my system! */
  284. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  285. multi = curl_multi_init ();
  286. if (multi == NULL)
  287. {
  288. curl_easy_cleanup (c);
  289. MHD_stop_daemon (d);
  290. return 512;
  291. }
  292. mret = curl_multi_add_handle (multi, c);
  293. if (mret != CURLM_OK)
  294. {
  295. curl_multi_cleanup (multi);
  296. curl_easy_cleanup (c);
  297. MHD_stop_daemon (d);
  298. return 1024;
  299. }
  300. start = time (NULL);
  301. while ((time (NULL) - start < 5) && (multi != NULL))
  302. {
  303. maxsock = MHD_INVALID_SOCKET;
  304. maxposixs = -1;
  305. FD_ZERO (&rs);
  306. FD_ZERO (&ws);
  307. FD_ZERO (&es);
  308. curl_multi_perform (multi, &running);
  309. mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
  310. if (mret != CURLM_OK)
  311. {
  312. curl_multi_remove_handle (multi, c);
  313. curl_multi_cleanup (multi);
  314. curl_easy_cleanup (c);
  315. MHD_stop_daemon (d);
  316. return 2048;
  317. }
  318. if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
  319. {
  320. curl_multi_remove_handle (multi, c);
  321. curl_multi_cleanup (multi);
  322. curl_easy_cleanup (c);
  323. MHD_stop_daemon (d);
  324. return 4096;
  325. }
  326. tv.tv_sec = 0;
  327. tv.tv_usec = 1000;
  328. if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
  329. {
  330. if (EINTR != errno)
  331. abort ();
  332. }
  333. curl_multi_perform (multi, &running);
  334. if (running == 0)
  335. {
  336. msg = curl_multi_info_read (multi, &running);
  337. if (msg == NULL)
  338. break;
  339. if (msg->msg == CURLMSG_DONE)
  340. {
  341. if (msg->data.result != CURLE_OK)
  342. printf ("%s failed at %s:%d: `%s'\n",
  343. "curl_multi_perform",
  344. __FILE__,
  345. __LINE__, curl_easy_strerror (msg->data.result));
  346. curl_multi_remove_handle (multi, c);
  347. curl_multi_cleanup (multi);
  348. curl_easy_cleanup (c);
  349. c = NULL;
  350. multi = NULL;
  351. }
  352. }
  353. MHD_run (d);
  354. }
  355. if (multi != NULL)
  356. {
  357. curl_multi_remove_handle (multi, c);
  358. curl_easy_cleanup (c);
  359. curl_multi_cleanup (multi);
  360. }
  361. MHD_stop_daemon (d);
  362. if (cbc.pos != strlen (TESTSTR))
  363. return 8192;
  364. if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
  365. return 16384;
  366. return 0;
  367. }
  368. static int
  369. testUnknownPortGet ()
  370. {
  371. struct MHD_Daemon *d;
  372. const union MHD_DaemonInfo *di;
  373. CURL *c;
  374. char buf[2048];
  375. struct CBC cbc;
  376. CURLcode errornum;
  377. struct sockaddr_in addr;
  378. socklen_t addr_len = sizeof(addr);
  379. memset(&addr, 0, sizeof(addr));
  380. addr.sin_family = AF_INET;
  381. addr.sin_port = 0;
  382. addr.sin_addr.s_addr = INADDR_ANY;
  383. cbc.buf = buf;
  384. cbc.size = 2048;
  385. cbc.pos = 0;
  386. d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
  387. 1, NULL, NULL, &ahc_echo, "GET",
  388. MHD_OPTION_SOCK_ADDR, &addr,
  389. MHD_OPTION_END);
  390. if (d == NULL)
  391. return 32768;
  392. di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
  393. if (di == NULL)
  394. return 65536;
  395. if (0 != getsockname(di->listen_fd, (struct sockaddr *) &addr, &addr_len))
  396. return 131072;
  397. if (addr.sin_family != AF_INET)
  398. return 26214;
  399. snprintf(buf, sizeof(buf), "http://127.0.0.1:%hu/",
  400. ntohs(addr.sin_port));
  401. c = curl_easy_init ();
  402. curl_easy_setopt (c, CURLOPT_URL, buf);
  403. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  404. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  405. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  406. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  407. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  408. if (oneone)
  409. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  410. else
  411. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  412. /* NOTE: use of CONNECTTIMEOUT without also
  413. setting NOSIGNAL results in really weird
  414. crashes on my system! */
  415. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  416. if (CURLE_OK != (errornum = curl_easy_perform (c)))
  417. {
  418. fprintf (stderr,
  419. "curl_easy_perform failed: `%s'\n",
  420. curl_easy_strerror (errornum));
  421. curl_easy_cleanup (c);
  422. MHD_stop_daemon (d);
  423. return 524288;
  424. }
  425. curl_easy_cleanup (c);
  426. MHD_stop_daemon (d);
  427. if (cbc.pos != strlen (TESTSTR))
  428. return 1048576;
  429. if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
  430. return 2097152;
  431. return 0;
  432. }
  433. int
  434. main (int argc, char *const *argv)
  435. {
  436. unsigned int errorCount = 0;
  437. const char *tmp;
  438. FILE *f;
  439. if ( (NULL == (tmp = getenv ("TMPDIR"))) &&
  440. (NULL == (tmp = getenv ("TMP"))) &&
  441. (NULL == (tmp = getenv ("TEMP"))) )
  442. tmp = "/tmp";
  443. sourcefile = malloc (strlen (tmp) + 32);
  444. sprintf (sourcefile,
  445. "%s/%s",
  446. tmp,
  447. "test-mhd-sendfile");
  448. f = fopen (sourcefile, "w");
  449. if (NULL == f)
  450. {
  451. fprintf (stderr, "failed to write test file\n");
  452. free (sourcefile);
  453. return 1;
  454. }
  455. fwrite (TESTSTR, strlen (TESTSTR), 1, f);
  456. fclose (f);
  457. oneone = (NULL != strrchr (argv[0], (int) '/')) ?
  458. (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
  459. if (0 != curl_global_init (CURL_GLOBAL_WIN32))
  460. return 2;
  461. errorCount += testInternalGet ();
  462. errorCount += testMultithreadedGet ();
  463. errorCount += testMultithreadedPoolGet ();
  464. errorCount += testExternalGet ();
  465. errorCount += testUnknownPortGet ();
  466. if (errorCount != 0)
  467. fprintf (stderr, "Error (code: %u)\n", errorCount);
  468. curl_global_cleanup ();
  469. unlink (sourcefile);
  470. free (sourcefile);
  471. return errorCount != 0; /* 0 == pass */
  472. }