aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/test_get.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/test_get.c')
-rw-r--r--src/testcurl/test_get.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/src/testcurl/test_get.c b/src/testcurl/test_get.c
new file mode 100644
index 00000000..45122cdb
--- /dev/null
+++ b/src/testcurl/test_get.c
@@ -0,0 +1,513 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2009, 2011 Christian Grothoff
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file daemontest_get.c
23 * @brief Testcase for libmicrohttpd GET operations
24 * TODO: test parsing of query
25 * @author Christian Grothoff
26 */
27
28#include "MHD_config.h"
29#include "platform.h"
30#include <curl/curl.h>
31#include <microhttpd.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35
36#ifdef __MINGW32__
37#define usleep(usec) (Sleep ((usec) / 1000),0)
38#endif
39
40#ifndef WINDOWS
41#include <unistd.h>
42#include <sys/socket.h>
43#endif
44
45static int oneone;
46
47struct CBC
48{
49 char *buf;
50 size_t pos;
51 size_t size;
52};
53
54static size_t
55copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
56{
57 struct CBC *cbc = ctx;
58
59 if (cbc->pos + size * nmemb > cbc->size)
60 return 0; /* overflow */
61 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
62 cbc->pos += size * nmemb;
63 return size * nmemb;
64}
65
66static int
67ahc_echo (void *cls,
68 struct MHD_Connection *connection,
69 const char *url,
70 const char *method,
71 const char *version,
72 const char *upload_data, size_t *upload_data_size,
73 void **unused)
74{
75 static int ptr;
76 const char *me = cls;
77 struct MHD_Response *response;
78 int ret;
79
80 if (0 != strcmp (me, method))
81 return MHD_NO; /* unexpected method */
82 if (&ptr != *unused)
83 {
84 *unused = &ptr;
85 return MHD_YES;
86 }
87 *unused = NULL;
88 response = MHD_create_response_from_buffer (strlen (url),
89 (void *) url,
90 MHD_RESPMEM_MUST_COPY);
91 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
92 MHD_destroy_response (response);
93 if (ret == MHD_NO)
94 abort ();
95 return ret;
96}
97
98
99static int
100testInternalGet (int poll_flag)
101{
102 struct MHD_Daemon *d;
103 CURL *c;
104 char buf[2048];
105 struct CBC cbc;
106 CURLcode errornum;
107
108 cbc.buf = buf;
109 cbc.size = 2048;
110 cbc.pos = 0;
111 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
112 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
113 if (d == NULL)
114 return 1;
115 c = curl_easy_init ();
116 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world");
117 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
118 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
119 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
120 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
121 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
122 if (oneone)
123 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
124 else
125 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
126 /* NOTE: use of CONNECTTIMEOUT without also
127 setting NOSIGNAL results in really weird
128 crashes on my system!*/
129 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
130 if (CURLE_OK != (errornum = curl_easy_perform (c)))
131 {
132 fprintf (stderr,
133 "curl_easy_perform failed: `%s'\n",
134 curl_easy_strerror (errornum));
135 curl_easy_cleanup (c);
136 MHD_stop_daemon (d);
137 return 2;
138 }
139 curl_easy_cleanup (c);
140 MHD_stop_daemon (d);
141 if (cbc.pos != strlen ("/hello_world"))
142 return 4;
143 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
144 return 8;
145 return 0;
146}
147
148static int
149testMultithreadedGet (int poll_flag)
150{
151 struct MHD_Daemon *d;
152 CURL *c;
153 char buf[2048];
154 struct CBC cbc;
155 CURLcode errornum;
156
157 cbc.buf = buf;
158 cbc.size = 2048;
159 cbc.pos = 0;
160 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
161 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
162 if (d == NULL)
163 return 16;
164 c = curl_easy_init ();
165 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
166 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
167 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
168 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
169 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
170 if (oneone)
171 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
172 else
173 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
174 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
175 /* NOTE: use of CONNECTTIMEOUT without also
176 setting NOSIGNAL results in really weird
177 crashes on my system! */
178 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
179 if (CURLE_OK != (errornum = curl_easy_perform (c)))
180 {
181 fprintf (stderr,
182 "curl_easy_perform failed: `%s'\n",
183 curl_easy_strerror (errornum));
184 curl_easy_cleanup (c);
185 MHD_stop_daemon (d);
186 return 32;
187 }
188 curl_easy_cleanup (c);
189 MHD_stop_daemon (d);
190 if (cbc.pos != strlen ("/hello_world"))
191 return 64;
192 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
193 return 128;
194 return 0;
195}
196
197static int
198testMultithreadedPoolGet (int poll_flag)
199{
200 struct MHD_Daemon *d;
201 CURL *c;
202 char buf[2048];
203 struct CBC cbc;
204 CURLcode errornum;
205
206 cbc.buf = buf;
207 cbc.size = 2048;
208 cbc.pos = 0;
209 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
210 1081, NULL, NULL, &ahc_echo, "GET",
211 MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END);
212 if (d == NULL)
213 return 16;
214 c = curl_easy_init ();
215 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1081/hello_world");
216 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
217 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
218 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
219 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
220 if (oneone)
221 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
222 else
223 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
224 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
225 /* NOTE: use of CONNECTTIMEOUT without also
226 setting NOSIGNAL results in really weird
227 crashes on my system!*/
228 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
229 if (CURLE_OK != (errornum = curl_easy_perform (c)))
230 {
231 fprintf (stderr,
232 "curl_easy_perform failed: `%s'\n",
233 curl_easy_strerror (errornum));
234 curl_easy_cleanup (c);
235 MHD_stop_daemon (d);
236 return 32;
237 }
238 curl_easy_cleanup (c);
239 MHD_stop_daemon (d);
240 if (cbc.pos != strlen ("/hello_world"))
241 return 64;
242 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
243 return 128;
244 return 0;
245}
246
247static int
248testExternalGet ()
249{
250 struct MHD_Daemon *d;
251 CURL *c;
252 char buf[2048];
253 struct CBC cbc;
254 CURLM *multi;
255 CURLMcode mret;
256 fd_set rs;
257 fd_set ws;
258 fd_set es;
259 int max;
260 int running;
261 struct CURLMsg *msg;
262 time_t start;
263 struct timeval tv;
264
265 multi = NULL;
266 cbc.buf = buf;
267 cbc.size = 2048;
268 cbc.pos = 0;
269 d = MHD_start_daemon (MHD_USE_DEBUG,
270 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
271 if (d == NULL)
272 return 256;
273 c = curl_easy_init ();
274 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world");
275 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
276 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
277 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
278 if (oneone)
279 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
280 else
281 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
282 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
283 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
284 /* NOTE: use of CONNECTTIMEOUT without also
285 setting NOSIGNAL results in really weird
286 crashes on my system! */
287 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
288
289
290 multi = curl_multi_init ();
291 if (multi == NULL)
292 {
293 curl_easy_cleanup (c);
294 MHD_stop_daemon (d);
295 return 512;
296 }
297 mret = curl_multi_add_handle (multi, c);
298 if (mret != CURLM_OK)
299 {
300 curl_multi_cleanup (multi);
301 curl_easy_cleanup (c);
302 MHD_stop_daemon (d);
303 return 1024;
304 }
305 start = time (NULL);
306 while ((time (NULL) - start < 5) && (multi != NULL))
307 {
308 max = 0;
309 FD_ZERO (&rs);
310 FD_ZERO (&ws);
311 FD_ZERO (&es);
312 curl_multi_perform (multi, &running);
313 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
314 if (mret != CURLM_OK)
315 {
316 curl_multi_remove_handle (multi, c);
317 curl_multi_cleanup (multi);
318 curl_easy_cleanup (c);
319 MHD_stop_daemon (d);
320 return 2048;
321 }
322 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
323 {
324 curl_multi_remove_handle (multi, c);
325 curl_multi_cleanup (multi);
326 curl_easy_cleanup (c);
327 MHD_stop_daemon (d);
328 return 4096;
329 }
330 tv.tv_sec = 0;
331 tv.tv_usec = 1000;
332 select (max + 1, &rs, &ws, &es, &tv);
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 ("/hello_world"))
363 return 8192;
364 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
365 return 16384;
366 return 0;
367}
368
369static int
370testUnknownPortGet (int poll_flag)
371{
372 struct MHD_Daemon *d;
373 const union MHD_DaemonInfo *di;
374 CURL *c;
375 char buf[2048];
376 struct CBC cbc;
377 CURLcode errornum;
378
379 struct sockaddr_in addr;
380 socklen_t addr_len = sizeof(addr);
381 memset(&addr, 0, sizeof(addr));
382 addr.sin_family = AF_INET;
383 addr.sin_port = 0;
384 addr.sin_addr.s_addr = INADDR_ANY;
385
386 cbc.buf = buf;
387 cbc.size = 2048;
388 cbc.pos = 0;
389 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
390 1, NULL, NULL, &ahc_echo, "GET",
391 MHD_OPTION_SOCK_ADDR, &addr,
392 MHD_OPTION_END);
393 if (d == NULL)
394 return 32768;
395
396 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
397 if (di == NULL)
398 return 65536;
399
400 if (0 != getsockname(di->listen_fd, &addr, &addr_len))
401 return 131072;
402
403 if (addr.sin_family != AF_INET)
404 return 26214;
405
406 snprintf(buf, sizeof(buf), "http://127.0.0.1:%hu/hello_world",
407 ntohs(addr.sin_port));
408
409 c = curl_easy_init ();
410 curl_easy_setopt (c, CURLOPT_URL, buf);
411 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
412 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
413 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
414 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
415 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
416 if (oneone)
417 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
418 else
419 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
420 /* NOTE: use of CONNECTTIMEOUT without also
421 setting NOSIGNAL results in really weird
422 crashes on my system! */
423 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
424 if (CURLE_OK != (errornum = curl_easy_perform (c)))
425 {
426 fprintf (stderr,
427 "curl_easy_perform failed: `%s'\n",
428 curl_easy_strerror (errornum));
429 curl_easy_cleanup (c);
430 MHD_stop_daemon (d);
431 return 524288;
432 }
433 curl_easy_cleanup (c);
434 MHD_stop_daemon (d);
435 if (cbc.pos != strlen ("/hello_world"))
436 return 1048576;
437 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
438 return 2097152;
439 return 0;
440}
441
442
443static int
444testStopRace (int poll_flag)
445{
446 struct sockaddr_in sin;
447 int fd;
448 struct MHD_Daemon *d;
449
450 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
451 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
452 if (d == NULL)
453 return 16;
454
455 fd = SOCKET (PF_INET, SOCK_STREAM, 0);
456 if (fd < 0)
457 {
458 fprintf(stderr, "socket: %m\n");
459 return 256;
460 }
461
462 memset(&sin, 0, sizeof(sin));
463 sin.sin_family = AF_INET;
464 sin.sin_port = htons(1081);
465 sin.sin_addr.s_addr = htonl(0x7f000001);
466
467 if (CONNECT (fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0)
468 {
469 fprintf(stderr, "connect: %m\n");
470 return 512;
471 }
472
473 /* printf("Waiting\n"); */
474 /* Let the thread get going. */
475 usleep(500000);
476
477 /* printf("Stopping daemon\n"); */
478 MHD_stop_daemon (d);
479
480 CLOSE (fd);
481
482 /* printf("good\n"); */
483 return 0;
484}
485
486
487
488int
489main (int argc, char *const *argv)
490{
491 unsigned int errorCount = 0;
492
493 oneone = NULL != strstr (argv[0], "11");
494 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
495 return 2;
496 errorCount += testInternalGet (0);
497 errorCount += testMultithreadedGet (0);
498 errorCount += testMultithreadedPoolGet (0);
499 errorCount += testUnknownPortGet (0);
500 errorCount += testStopRace (0);
501 errorCount += testExternalGet ();
502#ifndef WINDOWS
503 errorCount += testInternalGet (MHD_USE_POLL);
504 errorCount += testMultithreadedGet (MHD_USE_POLL);
505 errorCount += testMultithreadedPoolGet (MHD_USE_POLL);
506 errorCount += testUnknownPortGet (MHD_USE_POLL);
507 errorCount += testStopRace (MHD_USE_POLL);
508#endif
509 if (errorCount != 0)
510 fprintf (stderr, "Error (code: %u)\n", errorCount);
511 curl_global_cleanup ();
512 return errorCount != 0; /* 0 == pass */
513}