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