test_long_header.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2007 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_long_header.c
  19. * @brief Testcase for libmicrohttpd handling of very long headers
  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. #ifndef WINDOWS
  30. #include <unistd.h>
  31. #endif
  32. /**
  33. * We will set the memory available per connection to
  34. * half of this value, so the actual value does not have
  35. * to be big at all...
  36. */
  37. #define VERY_LONG (1024*10)
  38. static int oneone;
  39. static int
  40. apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
  41. {
  42. (void)cls;(void)addr;(void)addrlen; /* Unused. Silent compiler warning. */
  43. return MHD_YES;
  44. }
  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. (void)ptr;(void)ctx; /* Unused. Silent compiler warning. */
  55. return size * nmemb;
  56. }
  57. static int
  58. ahc_echo (void *cls,
  59. struct MHD_Connection *connection,
  60. const char *url,
  61. const char *method,
  62. const char *version,
  63. const char *upload_data, size_t *upload_data_size,
  64. void **unused)
  65. {
  66. const char *me = cls;
  67. struct MHD_Response *response;
  68. int ret;
  69. (void)version;(void)upload_data; /* Unused. Silent compiler warning. */
  70. (void)upload_data_size;(void)unused; /* Unused. Silent compiler warning. */
  71. if (0 != strcmp (me, method))
  72. return MHD_NO; /* unexpected method */
  73. response = MHD_create_response_from_buffer (strlen (url),
  74. (void *) url,
  75. MHD_RESPMEM_MUST_COPY);
  76. ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  77. MHD_destroy_response (response);
  78. return ret;
  79. }
  80. static int
  81. testLongUrlGet ()
  82. {
  83. struct MHD_Daemon *d;
  84. CURL *c;
  85. char buf[2048];
  86. struct CBC cbc;
  87. char *url;
  88. long code;
  89. int port;
  90. if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
  91. port = 0;
  92. else
  93. {
  94. port = 1330;
  95. if (oneone)
  96. port += 5;
  97. }
  98. cbc.buf = buf;
  99. cbc.size = 2048;
  100. cbc.pos = 0;
  101. d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */ ,
  102. port,
  103. &apc_all,
  104. NULL,
  105. &ahc_echo,
  106. "GET",
  107. MHD_OPTION_CONNECTION_MEMORY_LIMIT,
  108. (size_t) (VERY_LONG / 2), MHD_OPTION_END);
  109. if (d == NULL)
  110. return 1;
  111. if (0 == port)
  112. {
  113. const union MHD_DaemonInfo *dinfo;
  114. dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
  115. if (NULL == dinfo || 0 == dinfo->port)
  116. { MHD_stop_daemon (d); return 32; }
  117. port = (int)dinfo->port;
  118. }
  119. c = curl_easy_init ();
  120. url = malloc (VERY_LONG);
  121. if (url == NULL)
  122. {
  123. MHD_stop_daemon (d);
  124. return 1;
  125. }
  126. memset (url, 'a', VERY_LONG);
  127. url[VERY_LONG - 1] = '\0';
  128. memcpy (url, "http://127.0.0.1/", strlen ("http://127.0.0.1/"));
  129. curl_easy_setopt (c, CURLOPT_URL, url);
  130. curl_easy_setopt (c, CURLOPT_PORT, (long)port);
  131. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  132. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  133. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  134. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  135. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  136. if (oneone)
  137. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  138. else
  139. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  140. /* NOTE: use of CONNECTTIMEOUT without also
  141. setting NOSIGNAL results in really weird
  142. crashes on my system! */
  143. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  144. if (CURLE_OK == curl_easy_perform (c))
  145. {
  146. curl_easy_cleanup (c);
  147. MHD_stop_daemon (d);
  148. free (url);
  149. return 2;
  150. }
  151. if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
  152. {
  153. curl_easy_cleanup (c);
  154. MHD_stop_daemon (d);
  155. free (url);
  156. return 4;
  157. }
  158. curl_easy_cleanup (c);
  159. MHD_stop_daemon (d);
  160. free (url);
  161. if (code != MHD_HTTP_URI_TOO_LONG)
  162. return 8;
  163. return 0;
  164. }
  165. static int
  166. testLongHeaderGet ()
  167. {
  168. struct MHD_Daemon *d;
  169. CURL *c;
  170. char buf[2048];
  171. struct CBC cbc;
  172. char *url;
  173. long code;
  174. struct curl_slist *header = NULL;
  175. int port;
  176. if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
  177. port = 0;
  178. else
  179. {
  180. port = 1331;
  181. if (oneone)
  182. port += 5;
  183. }
  184. cbc.buf = buf;
  185. cbc.size = 2048;
  186. cbc.pos = 0;
  187. d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG */ ,
  188. port,
  189. &apc_all,
  190. NULL,
  191. &ahc_echo,
  192. "GET",
  193. MHD_OPTION_CONNECTION_MEMORY_LIMIT,
  194. (size_t) (VERY_LONG / 2), MHD_OPTION_END);
  195. if (d == NULL)
  196. return 16;
  197. if (0 == port)
  198. {
  199. const union MHD_DaemonInfo *dinfo;
  200. dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
  201. if (NULL == dinfo || 0 == dinfo->port)
  202. { MHD_stop_daemon (d); return 32; }
  203. port = (int)dinfo->port;
  204. }
  205. c = curl_easy_init ();
  206. url = malloc (VERY_LONG);
  207. if (url == NULL)
  208. {
  209. MHD_stop_daemon (d);
  210. return 16;
  211. }
  212. memset (url, 'a', VERY_LONG);
  213. url[VERY_LONG - 1] = '\0';
  214. url[VERY_LONG / 2] = ':';
  215. url[VERY_LONG / 2 + 1] = ' ';
  216. header = curl_slist_append (header, url);
  217. curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
  218. curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
  219. curl_easy_setopt (c, CURLOPT_PORT, (long)port);
  220. curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
  221. curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
  222. curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
  223. curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
  224. curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
  225. if (oneone)
  226. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  227. else
  228. curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  229. /* NOTE: use of CONNECTTIMEOUT without also
  230. setting NOSIGNAL results in really weird
  231. crashes on my system! */
  232. curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
  233. if (CURLE_OK == curl_easy_perform (c))
  234. {
  235. curl_easy_cleanup (c);
  236. MHD_stop_daemon (d);
  237. curl_slist_free_all (header);
  238. free (url);
  239. return 32;
  240. }
  241. if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
  242. {
  243. curl_slist_free_all (header);
  244. curl_easy_cleanup (c);
  245. MHD_stop_daemon (d);
  246. free (url);
  247. return 64;
  248. }
  249. curl_slist_free_all (header);
  250. curl_easy_cleanup (c);
  251. MHD_stop_daemon (d);
  252. free (url);
  253. if (code != MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE)
  254. return 128;
  255. return 0;
  256. }
  257. int
  258. main (int argc, char *const *argv)
  259. {
  260. unsigned int errorCount = 0;
  261. (void)argc; /* Unused. Silent compiler warning. */
  262. oneone = (NULL != strrchr (argv[0], (int) '/')) ?
  263. (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
  264. if (0 != curl_global_init (CURL_GLOBAL_WIN32))
  265. return 2;
  266. errorCount += testLongUrlGet ();
  267. errorCount += testLongHeaderGet ();
  268. if (errorCount != 0)
  269. fprintf (stderr, "Error (code: %u)\n", errorCount);
  270. curl_global_cleanup ();
  271. return errorCount != 0; /* 0 == pass */
  272. }