aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-01-18 17:16:14 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2021-02-24 19:46:31 +0300
commitd50159bf9987c018e9ca7ed4cd72390494678da1 (patch)
tree36412a970ce6624a793ff1b4b68e30ca3b7775aa /src/testcurl
parent7bbbcd63f987b5451a29d3e084e045fc2ba1d14a (diff)
downloadlibmicrohttpd-d50159bf9987c018e9ca7ed4cd72390494678da1.tar.gz
libmicrohttpd-d50159bf9987c018e9ca7ed4cd72390494678da1.zip
Implemented new function MHD_create_response_from_iovec()
Implemented the new function, related framework, and tests for iovec-based responses. The implementation is based on the patch provided by Lawrence Sebald and Damon N. Earp from NASA.
Diffstat (limited to 'src/testcurl')
-rw-r--r--src/testcurl/.gitignore2
-rw-r--r--src/testcurl/Makefile.am16
-rw-r--r--src/testcurl/https/.gitignore1
-rw-r--r--src/testcurl/https/Makefile.am16
-rw-r--r--src/testcurl/https/test_https_get_iovec.c421
-rw-r--r--src/testcurl/test_get_iovec.c757
6 files changed, 1211 insertions, 2 deletions
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore
index 0ca3ac3c..008262bd 100644
--- a/src/testcurl/.gitignore
+++ b/src/testcurl/.gitignore
@@ -116,3 +116,5 @@ test_patch11
116/test_add_conn_cleanup 116/test_add_conn_cleanup
117/test_add_conn_cleanup_nolisten 117/test_add_conn_cleanup_nolisten
118core 118core
119/test_get_iovec
120/test_get_iovec11
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index 78f2a076..d0580554 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -78,6 +78,7 @@ endif
78if HAVE_CURL 78if HAVE_CURL
79check_PROGRAMS = \ 79check_PROGRAMS = \
80 test_get \ 80 test_get \
81 test_get_iovec \
81 test_get_sendfile \ 82 test_get_sendfile \
82 test_delete \ 83 test_delete \
83 test_patch \ 84 test_patch \
@@ -89,6 +90,7 @@ check_PROGRAMS = \
89 test_parse_cookies \ 90 test_parse_cookies \
90 test_large_put \ 91 test_large_put \
91 test_get11 \ 92 test_get11 \
93 test_get_iovec11 \
92 test_get_sendfile11 \ 94 test_get_sendfile11 \
93 test_patch11 \ 95 test_patch11 \
94 test_put11 \ 96 test_put11 \
@@ -218,6 +220,12 @@ test_digestauth_with_arguments_LDADD = \
218 $(top_builddir)/src/microhttpd/libmicrohttpd.la \ 220 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
219 @LIBGCRYPT_LIBS@ @LIBCURL@ 221 @LIBGCRYPT_LIBS@ @LIBCURL@
220 222
223test_get_iovec_SOURCES = \
224 test_get_iovec.c mhd_has_in_name.h
225test_get_iovec_LDADD = \
226 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
227 @LIBCURL@
228
221test_get_sendfile_SOURCES = \ 229test_get_sendfile_SOURCES = \
222 test_get_sendfile.c mhd_has_in_name.h 230 test_get_sendfile.c mhd_has_in_name.h
223test_get_sendfile_LDADD = \ 231test_get_sendfile_LDADD = \
@@ -306,7 +314,7 @@ test_put_chunked_SOURCES = \
306test_put_chunked_LDADD = \ 314test_put_chunked_LDADD = \
307 $(top_builddir)/src/microhttpd/libmicrohttpd.la \ 315 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
308 @LIBCURL@ 316 @LIBCURL@
309 317
310test_add_conn_SOURCES = \ 318test_add_conn_SOURCES = \
311 test_add_conn.c $(top_srcdir)/src/microhttpd/test_helpers.h 319 test_add_conn.c $(top_srcdir)/src/microhttpd/test_helpers.h
312test_add_conn_CFLAGS = \ 320test_add_conn_CFLAGS = \
@@ -345,6 +353,12 @@ test_get11_LDADD = \
345 $(top_builddir)/src/microhttpd/libmicrohttpd.la \ 353 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
346 @LIBCURL@ 354 @LIBCURL@
347 355
356test_get_iovec11_SOURCES = \
357 test_get_iovec.c mhd_has_in_name.h
358test_get_iovec11_LDADD = \
359 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
360 @LIBCURL@
361
348test_get_sendfile11_SOURCES = \ 362test_get_sendfile11_SOURCES = \
349 test_get_sendfile.c mhd_has_in_name.h 363 test_get_sendfile.c mhd_has_in_name.h
350test_get_sendfile11_LDADD = \ 364test_get_sendfile11_LDADD = \
diff --git a/src/testcurl/https/.gitignore b/src/testcurl/https/.gitignore
index 966e1215..7175906e 100644
--- a/src/testcurl/https/.gitignore
+++ b/src/testcurl/https/.gitignore
@@ -53,4 +53,5 @@
53/mhds_multi_daemon_test 53/mhds_multi_daemon_test
54/tls_authentication_test 54/tls_authentication_test
55/tmp_ca_cert.pem 55/tmp_ca_cert.pem
56/test_https_get_iovec
56*.exe 57*.exe
diff --git a/src/testcurl/https/Makefile.am b/src/testcurl/https/Makefile.am
index 7d395ed1..7f568b33 100644
--- a/src/testcurl/https/Makefile.am
+++ b/src/testcurl/https/Makefile.am
@@ -1,4 +1,6 @@
1# This Makefile.am is in the public domain 1# This Makefile.am is in the public domain
2EMPTY_ITEM =
3
2SUBDIRS = . 4SUBDIRS = .
3 5
4if USE_COVERAGE 6if USE_COVERAGE
@@ -34,7 +36,9 @@ THREAD_ONLY_TESTS = \
34 test_https_time_out \ 36 test_https_time_out \
35 test_https_multi_daemon \ 37 test_https_multi_daemon \
36 test_https_get \ 38 test_https_get \
37 test_empty_response 39 test_empty_response \
40 test_https_get_iovec \
41 $(EMPTY_ITEM)
38 42
39check_PROGRAMS = \ 43check_PROGRAMS = \
40 test_https_get_select 44 test_https_get_select
@@ -155,6 +159,16 @@ test_https_get_LDADD = \
155 $(top_builddir)/src/microhttpd/libmicrohttpd.la \ 159 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
156 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) @LIBGCRYPT_LIBS@ @LIBCURL@ 160 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) @LIBGCRYPT_LIBS@ @LIBCURL@
157 161
162test_https_get_iovec_SOURCES = \
163 test_https_get_iovec.c \
164 tls_test_keys.h \
165 tls_test_common.h \
166 tls_test_common.c
167test_https_get_iovec_LDADD = \
168 $(top_builddir)/src/testcurl/libcurl_version_check.a \
169 $(top_builddir)/src/microhttpd/libmicrohttpd.la \
170 $(MHD_TLS_LIB_LDFLAGS) $(MHD_TLS_LIBDEPS) @LIBGCRYPT_LIBS@ @LIBCURL@
171
158if HAVE_GNUTLS_SNI 172if HAVE_GNUTLS_SNI
159test_https_sni_SOURCES = \ 173test_https_sni_SOURCES = \
160 test_https_sni.c \ 174 test_https_sni.c \
diff --git a/src/testcurl/https/test_https_get_iovec.c b/src/testcurl/https/test_https_get_iovec.c
new file mode 100644
index 00000000..28d5cbfc
--- /dev/null
+++ b/src/testcurl/https/test_https_get_iovec.c
@@ -0,0 +1,421 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2021 Christian Grothoff
4 Copyright (C) 2016-2021 Evgeny Grin
5
6 libmicrohttpd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 libmicrohttpd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with libmicrohttpd; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file test_https_get_iovec.c
24 * @brief Testcase for libmicrohttpd HTTPS GET operations using an iovec
25 * @author Sagie Amir
26 * @author Karlson2k (Evgeny Grin)
27 * @author Lawrence Sebald
28 */
29
30/*
31 * This testcase is derived from the test_https_get.c testcase. This version
32 * adds the usage of a scatter/gather array for storing the response data.
33 */
34
35#include "platform.h"
36#include "microhttpd.h"
37#include <limits.h>
38#include <sys/stat.h>
39#include <curl/curl.h>
40#ifdef MHD_HTTPS_REQUIRE_GRYPT
41#include <gcrypt.h>
42#endif /* MHD_HTTPS_REQUIRE_GRYPT */
43#include "tls_test_common.h"
44
45extern const char srv_signed_cert_pem[];
46extern const char srv_signed_key_pem[];
47
48
49static int global_port;
50
51/* Use large enough pieces (>16KB) to test partially consumed
52 * data as TLS doesn't take more than 16KB by a single call. */
53#define TESTSTR_IOVLEN 20480
54#define TESTSTR_IOVCNT 30
55#define TESTSTR_SIZE (TESTSTR_IOVCNT * TESTSTR_IOVLEN)
56
57
58static void
59iov_free_callback (void *cls)
60{
61 free (cls);
62}
63
64
65static int
66check_read_data (const void *ptr, size_t len)
67{
68 const int *buf;
69 size_t i;
70
71 if (len % sizeof(int))
72 return -1;
73
74 buf = (const int *) ptr;
75
76 for (i = 0; i < len / sizeof(int); ++i)
77 {
78 if (buf[i] != (int) i)
79 return -1;
80 }
81
82 return 0;
83}
84
85
86static enum MHD_Result
87iovec_ahc (void *cls,
88 struct MHD_Connection *connection,
89 const char *url,
90 const char *method,
91 const char *version,
92 const char *upload_data,
93 size_t *upload_data_size,
94 void **ptr)
95{
96 static int aptr;
97 struct MHD_Response *response;
98 enum MHD_Result ret;
99 int *data;
100 struct MHD_IoVec iov[TESTSTR_IOVCNT];
101 int i;
102 int j;
103 (void) cls; (void) url; (void) version; /* Unused. Silent compiler warning. */
104 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
105
106 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
107 return MHD_NO; /* unexpected method */
108 if (&aptr != *ptr)
109 {
110 /* do never respond on first call */
111 *ptr = &aptr;
112 return MHD_YES;
113 }
114 *ptr = NULL; /* reset when done */
115
116 /* Create some test data. */
117 if (NULL == (data = malloc (TESTSTR_SIZE)))
118 return MHD_NO;
119
120 for (j = 0; j < TESTSTR_IOVCNT; ++j)
121 {
122 /* Assign chunks of memory area in the reverse order
123 * to make non-continous set of data therefore
124 * possible buffer overruns could be detected */
125 iov[j].iov_base = data + (((TESTSTR_IOVCNT - 1) - j)
126 * (TESTSTR_SIZE / TESTSTR_IOVCNT
127 / sizeof(int)));
128 iov[j].iov_len = TESTSTR_SIZE / TESTSTR_IOVCNT;
129
130 for (i = 0; i < (int) (TESTSTR_IOVLEN / sizeof(int)); ++i)
131 ((int*) iov[j].iov_base)[i] = i + (j * TESTSTR_IOVLEN / sizeof(int));
132 }
133
134 response = MHD_create_response_from_iovec (iov,
135 TESTSTR_IOVCNT,
136 &iov_free_callback,
137 data);
138 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
139 MHD_destroy_response (response);
140 return ret;
141}
142
143
144static int
145test_iovec_transfer (void *cls,
146 int port,
147 const char *cipher_suite,
148 int proto_version)
149{
150 int len;
151 int ret = 0;
152 struct CBC cbc;
153 char url[255];
154 (void) cls; /* Unused. Silent compiler warning. */
155
156 len = TESTSTR_SIZE;
157 if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
158 {
159 fprintf (stderr, MHD_E_MEM);
160 return -1;
161 }
162 cbc.size = len;
163 cbc.pos = 0;
164
165 if (gen_test_file_url (url,
166 sizeof (url),
167 port))
168 {
169 ret = -1;
170 goto cleanup;
171 }
172
173 if (CURLE_OK !=
174 send_curl_req (url, &cbc, cipher_suite, proto_version))
175 {
176 ret = -1;
177 goto cleanup;
178 }
179
180 /* compare test file & daemon response */
181 if ((cbc.pos != TESTSTR_SIZE) ||
182 (0 != check_read_data (cbc.buf, cbc.pos)))
183 {
184 fprintf (stderr, "Error: local file & received file differ.\n");
185 ret = -1;
186 }
187cleanup:
188 free (cbc.buf);
189 return ret;
190}
191
192
193/* perform a HTTP GET request via SSL/TLS */
194static int
195test_secure_get (FILE *test_fd,
196 const char *cipher_suite,
197 int proto_version)
198{
199 int ret;
200 struct MHD_Daemon *d;
201 int port;
202
203 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
204 port = 0;
205 else
206 port = 3041;
207
208 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
209 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS
210 | MHD_USE_ERROR_LOG, port,
211 NULL, NULL,
212 &iovec_ahc, NULL,
213 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
214 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
215 MHD_OPTION_END);
216
217 if (d == NULL)
218 {
219 fprintf (stderr, MHD_E_SERVER_INIT);
220 return -1;
221 }
222 if (0 == port)
223 {
224 const union MHD_DaemonInfo *dinfo;
225 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
226 if ((NULL == dinfo) || (0 == dinfo->port) )
227 {
228 MHD_stop_daemon (d); return -1;
229 }
230 port = (int) dinfo->port;
231 }
232
233 ret = test_iovec_transfer (test_fd,
234 port,
235 cipher_suite,
236 proto_version);
237
238 MHD_stop_daemon (d);
239 return ret;
240}
241
242
243static enum MHD_Result
244ahc_empty (void *cls,
245 struct MHD_Connection *connection,
246 const char *url,
247 const char *method,
248 const char *version,
249 const char *upload_data,
250 size_t *upload_data_size,
251 void **unused)
252{
253 static int ptr;
254 struct MHD_Response *response;
255 enum MHD_Result ret;
256 struct MHD_IoVec iov;
257 (void) cls;
258 (void) url;
259 (void) url;
260 (void) version; /* Unused. Silent compiler warning. */
261 (void) upload_data;
262 (void) upload_data_size; /* Unused. Silent compiler warning. */
263
264 if (0 != strcasecmp ("GET",
265 method))
266 return MHD_NO; /* unexpected method */
267 if (&ptr != *unused)
268 {
269 *unused = &ptr;
270 return MHD_YES;
271 }
272 *unused = NULL;
273
274 iov.iov_base = NULL;
275 iov.iov_len = 0;
276
277 response = MHD_create_response_from_iovec (&iov,
278 1,
279 NULL,
280 NULL);
281 ret = MHD_queue_response (connection,
282 MHD_HTTP_OK,
283 response);
284 MHD_destroy_response (response);
285 if (ret == MHD_NO)
286 {
287 fprintf (stderr, "Failed to queue response.\n");
288 _exit (20);
289 }
290 return ret;
291}
292
293
294static int
295curlExcessFound (CURL *c,
296 curl_infotype type,
297 char *data,
298 size_t size,
299 void *cls)
300{
301 static const char *excess_found = "Excess found";
302 const size_t str_size = strlen (excess_found);
303 (void) c; /* Unused. Silence compiler warning. */
304
305 if ((CURLINFO_TEXT == type)
306 && (size >= str_size)
307 && (0 == strncmp (excess_found, data, str_size)))
308 *(int *) cls = 1;
309 return 0;
310}
311
312
313static int
314testEmptyGet (int poll_flag)
315{
316 struct MHD_Daemon *d;
317 CURL *c;
318 char buf[2048];
319 struct CBC cbc;
320 CURLcode errornum;
321 int excess_found = 0;
322
323
324 if ( (0 == global_port) &&
325 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
326 {
327 global_port = 1225;
328
329 }
330
331 cbc.buf = buf;
332 cbc.size = 2048;
333 cbc.pos = 0;
334 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
335 | poll_flag | MHD_USE_TLS,
336 global_port, NULL, NULL,
337 &ahc_empty, NULL,
338 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
339 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
340 MHD_OPTION_END);
341 if (d == NULL)
342 return 4194304;
343 if (0 == global_port)
344 {
345 const union MHD_DaemonInfo *dinfo;
346 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
347 if ((NULL == dinfo) || (0 == dinfo->port) )
348 {
349 MHD_stop_daemon (d); return 32;
350 }
351 global_port = (int) dinfo->port;
352 }
353 c = curl_easy_init ();
354 curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/");
355 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
356 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
357 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
358 curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound);
359 curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found);
360 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
361 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
362 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
363 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
364 curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L);
365 curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L);
366 /* NOTE: use of CONNECTTIMEOUT without also
367 setting NOSIGNAL results in really weird
368 crashes on my system!*/
369 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
370 if (CURLE_OK != (errornum = curl_easy_perform (c)))
371 {
372 fprintf (stderr,
373 "curl_easy_perform failed: `%s'\n",
374 curl_easy_strerror (errornum));
375 curl_easy_cleanup (c);
376 MHD_stop_daemon (d);
377 return 8388608;
378 }
379 curl_easy_cleanup (c);
380 MHD_stop_daemon (d);
381 if (cbc.pos != 0)
382 return 16777216;
383 if (excess_found)
384 return 33554432;
385 return 0;
386}
387
388
389int
390main (int argc, char *const *argv)
391{
392 unsigned int errorCount = 0;
393 const char *aes256_sha_tlsv1 = "AES256-SHA";
394 (void) argc; (void) argv; /* Unused. Silent compiler warning. */
395
396#ifdef MHD_HTTPS_REQUIRE_GRYPT
397 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
398#ifdef GCRYCTL_INITIALIZATION_FINISHED
399 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
400#endif
401#endif /* MHD_HTTPS_REQUIRE_GRYPT */
402 if (! testsuite_curl_global_init ())
403 return 99;
404 if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
405 {
406 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n");
407 curl_global_cleanup ();
408 return 77;
409 }
410
411 if (curl_uses_nss_ssl () == 0)
412 {
413 aes256_sha_tlsv1 = "rsa_aes_256_sha";
414 }
415 errorCount +=
416 test_secure_get (NULL, aes256_sha_tlsv1, CURL_SSLVERSION_TLSv1);
417 errorCount += testEmptyGet (0);
418 curl_global_cleanup ();
419
420 return errorCount != 0 ? 1 : 0;
421}
diff --git a/src/testcurl/test_get_iovec.c b/src/testcurl/test_get_iovec.c
new file mode 100644
index 00000000..1d817851
--- /dev/null
+++ b/src/testcurl/test_get_iovec.c
@@ -0,0 +1,757 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2021 Christian Grothoff
4 Copyright (C) 2014-2021 Evgeny Grin
5
6 libmicrohttpd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
10
11 libmicrohttpd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with libmicrohttpd; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file test_get_iovec.c
24 * @brief Testcase for libmicrohttpd response from scatter/gather array
25 * @author Christian Grothoff
26 * @author Karlson2k (Evgeny Grin)
27 * @author Lawrence Sebald
28 */
29
30/*
31 * This test is largely derived from the test_get_sendfile.c file, with the
32 * daemon using MHD_create_response_from_iovec instead of working from an fd.
33 */
34
35#include "MHD_config.h"
36#include "platform.h"
37#include <curl/curl.h>
38#include <microhttpd.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42#include <sys/types.h>
43#include <fcntl.h>
44#include "mhd_sockets.h"
45#include "mhd_has_in_name.h"
46
47#ifndef WINDOWS
48#include <sys/socket.h>
49#include <unistd.h>
50#endif
51
52#if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
53#undef MHD_CPU_COUNT
54#endif
55#if ! defined(MHD_CPU_COUNT)
56#define MHD_CPU_COUNT 2
57#endif
58
59#define TESTSTR_IOVLEN 20480
60#define TESTSTR_IOVCNT 20
61#define TESTSTR_SIZE (TESTSTR_IOVCNT * TESTSTR_IOVLEN)
62
63static int oneone;
64
65static int readbuf[TESTSTR_SIZE * 2 / sizeof(int)];
66
67struct CBC
68{
69 char *buf;
70 size_t pos;
71 size_t size;
72};
73
74
75static size_t
76copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
77{
78 struct CBC *cbc = ctx;
79
80 if (cbc->pos + size * nmemb > cbc->size)
81 _exit (7); /* overflow */
82 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
83 cbc->pos += size * nmemb;
84 return size * nmemb;
85}
86
87
88static void
89iov_free_callback (void *cls)
90{
91 free (cls);
92}
93
94
95static void
96iovncont_free_callback (void *cls)
97{
98 struct MHD_IoVec *iov = (struct MHD_IoVec *) cls;
99 int i;
100
101 for (i = 0; i < TESTSTR_IOVCNT; ++i)
102 {
103 free (iov[i].iov_base);
104 }
105
106 free (iov);
107}
108
109
110static int
111check_read_data (const void *ptr, size_t len)
112{
113 const int *buf;
114 size_t i;
115
116 if (len % sizeof(int))
117 return -1;
118
119 buf = (const int *) ptr;
120
121 for (i = 0; i < len / sizeof(int); ++i)
122 {
123 if (buf[i] != (int) i)
124 return -1;
125 }
126
127 return 0;
128}
129
130
131static enum MHD_Result
132ahc_echo (void *cls,
133 struct MHD_Connection *connection,
134 const char *url,
135 const char *method,
136 const char *version,
137 const char *upload_data, size_t *upload_data_size,
138 void **unused)
139{
140 static int ptr;
141 const char *me = cls;
142 struct MHD_Response *response;
143 enum MHD_Result ret;
144 int *data;
145 struct MHD_IoVec iov[TESTSTR_IOVCNT];
146 int i;
147 (void) url; (void) version; /* Unused. Silent compiler warning. */
148 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
149
150 if (0 != strcmp (me, method))
151 return MHD_NO; /* unexpected method */
152 if (&ptr != *unused)
153 {
154 *unused = &ptr;
155 return MHD_YES;
156 }
157 *unused = NULL;
158
159 /* Create some test data. */
160 if (NULL == (data = malloc (TESTSTR_SIZE)))
161 return MHD_NO;
162
163 for (i = 0; i < (int) (TESTSTR_SIZE / sizeof(int)); ++i)
164 {
165 data[i] = i;
166 }
167
168 for (i = 0; i < TESTSTR_IOVCNT; ++i)
169 {
170 iov[i].iov_base = data + (i * (TESTSTR_SIZE / TESTSTR_IOVCNT
171 / sizeof(int)));
172 iov[i].iov_len = TESTSTR_SIZE / TESTSTR_IOVCNT;
173 }
174
175 response = MHD_create_response_from_iovec (iov,
176 TESTSTR_IOVCNT,
177 &iov_free_callback,
178 data);
179 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
180 MHD_destroy_response (response);
181 if (ret == MHD_NO)
182 abort ();
183 return ret;
184}
185
186
187static enum MHD_Result
188ncont_echo (void *cls,
189 struct MHD_Connection *connection,
190 const char *url,
191 const char *method,
192 const char *version,
193 const char *upload_data, size_t *upload_data_size,
194 void **unused)
195{
196 static int ptr;
197 const char *me = cls;
198 struct MHD_Response *response;
199 enum MHD_Result ret;
200 int *data;
201 struct MHD_IoVec *iov;
202 int i, j;
203 (void) url; (void) version; /* Unused. Silent compiler warning. */
204 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
205
206 if (0 != strcmp (me, method))
207 return MHD_NO; /* unexpected method */
208 if (&ptr != *unused)
209 {
210 *unused = &ptr;
211 return MHD_YES;
212 }
213 *unused = NULL;
214
215 if (NULL == (iov = malloc (sizeof(struct MHD_IoVec) * TESTSTR_IOVCNT)))
216 return MHD_NO;
217
218 memset (iov, 0, sizeof(struct MHD_IoVec) * TESTSTR_IOVCNT);
219
220 /* Create some test data. */
221 for (j = TESTSTR_IOVCNT - 1; j >= 0; --j)
222 {
223 if (NULL == (data = malloc (TESTSTR_IOVLEN)))
224 goto err_out;
225
226 iov[j].iov_base = data;
227 iov[j].iov_len = TESTSTR_IOVLEN;
228
229 for (i = 0; i < (int) (TESTSTR_IOVLEN / sizeof(int)); ++i)
230 {
231 data[i] = i + (j * TESTSTR_IOVLEN / sizeof(int));
232 }
233 }
234
235 response = MHD_create_response_from_iovec (iov,
236 TESTSTR_IOVCNT,
237 &iovncont_free_callback,
238 iov);
239 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
240 MHD_destroy_response (response);
241 if (ret == MHD_NO)
242 abort ();
243 return ret;
244
245err_out:
246 for (j = 0; j < TESTSTR_IOVCNT; ++j)
247 {
248 if (NULL != iov[j].iov_base)
249 free (iov[j].iov_base);
250 }
251
252 return MHD_NO;
253}
254
255
256static int
257testInternalGet (bool contiguous)
258{
259 struct MHD_Daemon *d;
260 CURL *c;
261 struct CBC cbc;
262 CURLcode errornum;
263 int port;
264
265 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
266 port = 0;
267 else
268 {
269 port = 1200;
270 if (oneone)
271 port += 10;
272 }
273
274 cbc.buf = (char*) readbuf;
275 cbc.size = sizeof(readbuf);
276 cbc.pos = 0;
277
278 if (contiguous)
279 {
280 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
281 port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
282 }
283 else
284 {
285 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
286 port, NULL, NULL, &ncont_echo, "GET", MHD_OPTION_END);
287 }
288
289 if (d == NULL)
290 return 1;
291 if (0 == port)
292 {
293 const union MHD_DaemonInfo *dinfo;
294 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
295 if ((NULL == dinfo) || (0 == dinfo->port) )
296 {
297 MHD_stop_daemon (d); return 32;
298 }
299 port = (int) dinfo->port;
300 }
301 c = curl_easy_init ();
302 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
303 curl_easy_setopt (c, CURLOPT_PORT, (long) port);
304 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
305 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
306 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
307 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
308 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
309 if (oneone)
310 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
311 else
312 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
313 /* NOTE: use of CONNECTTIMEOUT without also
314 setting NOSIGNAL results in really weird
315 crashes on my system!*/
316 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
317 if (CURLE_OK != (errornum = curl_easy_perform (c)))
318 {
319 fprintf (stderr,
320 "curl_easy_perform failed: `%s'\n",
321 curl_easy_strerror (errornum));
322 curl_easy_cleanup (c);
323 MHD_stop_daemon (d);
324 return 2;
325 }
326 curl_easy_cleanup (c);
327 MHD_stop_daemon (d);
328 if (cbc.pos != TESTSTR_SIZE)
329 return 4;
330 if (0 != check_read_data (cbc.buf, cbc.pos))
331 return 8;
332 return 0;
333}
334
335
336static int
337testMultithreadedGet ()
338{
339 struct MHD_Daemon *d;
340 CURL *c;
341 struct CBC cbc;
342 CURLcode errornum;
343 int port;
344
345 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
346 port = 0;
347 else
348 {
349 port = 1201;
350 if (oneone)
351 port += 10;
352 }
353
354 cbc.buf = (char*) readbuf;
355 cbc.size = sizeof(readbuf);
356 cbc.pos = 0;
357 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
358 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
359 | MHD_USE_AUTO,
360 port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
361 if (d == NULL)
362 return 16;
363 if (0 == port)
364 {
365 const union MHD_DaemonInfo *dinfo;
366 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
367 if ((NULL == dinfo) || (0 == dinfo->port) )
368 {
369 MHD_stop_daemon (d); return 32;
370 }
371 port = (int) dinfo->port;
372 }
373 c = curl_easy_init ();
374 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
375 curl_easy_setopt (c, CURLOPT_PORT, (long) port);
376 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
377 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
378 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
379 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
380 if (oneone)
381 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
382 else
383 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
384 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
385 /* NOTE: use of CONNECTTIMEOUT without also
386 setting NOSIGNAL results in really weird
387 crashes on my system! */
388 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
389 if (CURLE_OK != (errornum = curl_easy_perform (c)))
390 {
391 fprintf (stderr,
392 "curl_easy_perform failed: `%s'\n",
393 curl_easy_strerror (errornum));
394 curl_easy_cleanup (c);
395 MHD_stop_daemon (d);
396 return 32;
397 }
398 curl_easy_cleanup (c);
399 MHD_stop_daemon (d);
400 if (cbc.pos != TESTSTR_SIZE)
401 return 64;
402 if (0 != check_read_data (cbc.buf, cbc.pos))
403 return 128;
404 return 0;
405}
406
407
408static int
409testMultithreadedPoolGet ()
410{
411 struct MHD_Daemon *d;
412 CURL *c;
413 struct CBC cbc;
414 CURLcode errornum;
415 int port;
416
417 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
418 port = 0;
419 else
420 {
421 port = 1202;
422 if (oneone)
423 port += 10;
424 }
425
426 cbc.buf = (char*) readbuf;
427 cbc.size = sizeof(readbuf);
428 cbc.pos = 0;
429 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
430 | MHD_USE_AUTO,
431 port, NULL, NULL, &ahc_echo, "GET",
432 MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT,
433 MHD_OPTION_END);
434 if (d == NULL)
435 return 16;
436 if (0 == port)
437 {
438 const union MHD_DaemonInfo *dinfo;
439 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
440 if ((NULL == dinfo) || (0 == dinfo->port) )
441 {
442 MHD_stop_daemon (d); return 32;
443 }
444 port = (int) dinfo->port;
445 }
446 c = curl_easy_init ();
447 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
448 curl_easy_setopt (c, CURLOPT_PORT, (long) port);
449 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
450 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
451 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
452 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
453 if (oneone)
454 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
455 else
456 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
457 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
458 /* NOTE: use of CONNECTTIMEOUT without also
459 setting NOSIGNAL results in really weird
460 crashes on my system!*/
461 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
462 if (CURLE_OK != (errornum = curl_easy_perform (c)))
463 {
464 fprintf (stderr,
465 "curl_easy_perform failed: `%s'\n",
466 curl_easy_strerror (errornum));
467 curl_easy_cleanup (c);
468 MHD_stop_daemon (d);
469 return 32;
470 }
471 curl_easy_cleanup (c);
472 MHD_stop_daemon (d);
473 if (cbc.pos != TESTSTR_SIZE)
474 return 64;
475 if (0 != check_read_data (cbc.buf, cbc.pos))
476 return 128;
477 return 0;
478}
479
480
481static int
482testExternalGet ()
483{
484 struct MHD_Daemon *d;
485 CURL *c;
486 struct CBC cbc;
487 CURLM *multi;
488 CURLMcode mret;
489 fd_set rs;
490 fd_set ws;
491 fd_set es;
492 MHD_socket maxsock;
493#ifdef MHD_WINSOCK_SOCKETS
494 int maxposixs; /* Max socket number unused on W32 */
495#else /* MHD_POSIX_SOCKETS */
496#define maxposixs maxsock
497#endif /* MHD_POSIX_SOCKETS */
498 int running;
499 struct CURLMsg *msg;
500 time_t start;
501 struct timeval tv;
502 int port;
503
504 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
505 port = 0;
506 else
507 {
508 port = 1203;
509 if (oneone)
510 port += 10;
511 }
512
513 multi = NULL;
514 cbc.buf = (char*) readbuf;
515 cbc.size = sizeof(readbuf);
516 cbc.pos = 0;
517 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
518 port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
519 if (d == NULL)
520 return 256;
521 if (0 == port)
522 {
523 const union MHD_DaemonInfo *dinfo;
524 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
525 if ((NULL == dinfo) || (0 == dinfo->port) )
526 {
527 MHD_stop_daemon (d); return 32;
528 }
529 port = (int) dinfo->port;
530 }
531 c = curl_easy_init ();
532 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
533 curl_easy_setopt (c, CURLOPT_PORT, (long) port);
534 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
535 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
536 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
537 if (oneone)
538 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
539 else
540 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
541 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
542 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
543 /* NOTE: use of CONNECTTIMEOUT without also
544 setting NOSIGNAL results in really weird
545 crashes on my system! */
546 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
547
548
549 multi = curl_multi_init ();
550 if (multi == NULL)
551 {
552 curl_easy_cleanup (c);
553 MHD_stop_daemon (d);
554 return 512;
555 }
556 mret = curl_multi_add_handle (multi, c);
557 if (mret != CURLM_OK)
558 {
559 curl_multi_cleanup (multi);
560 curl_easy_cleanup (c);
561 MHD_stop_daemon (d);
562 return 1024;
563 }
564 start = time (NULL);
565 while ((time (NULL) - start < 5) && (multi != NULL))
566 {
567 maxsock = MHD_INVALID_SOCKET;
568 maxposixs = -1;
569 FD_ZERO (&rs);
570 FD_ZERO (&ws);
571 FD_ZERO (&es);
572 curl_multi_perform (multi, &running);
573 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
574 if (mret != CURLM_OK)
575 {
576 curl_multi_remove_handle (multi, c);
577 curl_multi_cleanup (multi);
578 curl_easy_cleanup (c);
579 MHD_stop_daemon (d);
580 return 2048;
581 }
582 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
583 {
584 curl_multi_remove_handle (multi, c);
585 curl_multi_cleanup (multi);
586 curl_easy_cleanup (c);
587 MHD_stop_daemon (d);
588 return 4096;
589 }
590 tv.tv_sec = 0;
591 tv.tv_usec = 1000;
592 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
593 {
594#ifdef MHD_POSIX_SOCKETS
595 if (EINTR != errno)
596 abort ();
597#else
598 if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 !=
599 ws.
600 fd_count)
601 || (0 != es.fd_count) )
602 abort ();
603 Sleep (1000);
604#endif
605 }
606 curl_multi_perform (multi, &running);
607 if (running == 0)
608 {
609 msg = curl_multi_info_read (multi, &running);
610 if (msg == NULL)
611 break;
612 if (msg->msg == CURLMSG_DONE)
613 {
614 if (msg->data.result != CURLE_OK)
615 printf ("%s failed at %s:%d: `%s'\n",
616 "curl_multi_perform",
617 __FILE__,
618 __LINE__, curl_easy_strerror (msg->data.result));
619 curl_multi_remove_handle (multi, c);
620 curl_multi_cleanup (multi);
621 curl_easy_cleanup (c);
622 c = NULL;
623 multi = NULL;
624 }
625 }
626 MHD_run (d);
627 }
628 if (multi != NULL)
629 {
630 curl_multi_remove_handle (multi, c);
631 curl_easy_cleanup (c);
632 curl_multi_cleanup (multi);
633 }
634 MHD_stop_daemon (d);
635 if (cbc.pos != TESTSTR_SIZE)
636 return 8192;
637 if (0 != check_read_data (cbc.buf, cbc.pos))
638 return 16384;
639 return 0;
640}
641
642
643static int
644testUnknownPortGet ()
645{
646 struct MHD_Daemon *d;
647 const union MHD_DaemonInfo *di;
648 CURL *c;
649 struct CBC cbc;
650 CURLcode errornum;
651 int port;
652 char buf[2048];
653
654 struct sockaddr_in addr;
655 socklen_t addr_len = sizeof(addr);
656 memset (&addr, 0, sizeof(addr));
657 addr.sin_family = AF_INET;
658 addr.sin_port = 0;
659 addr.sin_addr.s_addr = INADDR_ANY;
660
661 cbc.buf = (char*) readbuf;
662 cbc.size = sizeof(readbuf);
663 cbc.pos = 0;
664 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
665 0, NULL, NULL, &ahc_echo, "GET",
666 MHD_OPTION_SOCK_ADDR, &addr,
667 MHD_OPTION_END);
668 if (d == NULL)
669 return 32768;
670
671 if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
672 {
673 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
674 if (di == NULL)
675 return 65536;
676
677 if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len))
678 return 131072;
679
680 if (addr.sin_family != AF_INET)
681 return 26214;
682 port = (int) ntohs (addr.sin_port);
683 }
684 else
685 {
686 const union MHD_DaemonInfo *dinfo;
687 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
688 if ((NULL == dinfo) || (0 == dinfo->port) )
689 {
690 MHD_stop_daemon (d); return 32;
691 }
692 port = (int) dinfo->port;
693 }
694
695 snprintf (buf, sizeof(buf), "http://127.0.0.1:%d/",
696 port);
697
698 c = curl_easy_init ();
699 curl_easy_setopt (c, CURLOPT_URL, buf);
700 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
701 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
702 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
703 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
704 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
705 if (oneone)
706 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
707 else
708 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
709 /* NOTE: use of CONNECTTIMEOUT without also
710 setting NOSIGNAL results in really weird
711 crashes on my system! */
712 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
713 if (CURLE_OK != (errornum = curl_easy_perform (c)))
714 {
715 fprintf (stderr,
716 "curl_easy_perform failed: `%s'\n",
717 curl_easy_strerror (errornum));
718 curl_easy_cleanup (c);
719 MHD_stop_daemon (d);
720 return 524288;
721 }
722 curl_easy_cleanup (c);
723 MHD_stop_daemon (d);
724 if (cbc.pos != TESTSTR_SIZE)
725 return 1048576;
726 if (0 != check_read_data (cbc.buf, cbc.pos))
727 return 2097152;
728 return 0;
729}
730
731
732int
733main (int argc, char *const *argv)
734{
735 unsigned int errorCount = 0;
736 (void) argc; /* Unused. Silent compiler warning. */
737
738 if ((NULL == argv) || (0 == argv[0]))
739 return 99;
740 oneone = has_in_name (argv[0], "11");
741
742 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
743 return 2;
744 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
745 {
746 errorCount += testInternalGet (true);
747 errorCount += testInternalGet (false);
748 errorCount += testMultithreadedGet ();
749 errorCount += testMultithreadedPoolGet ();
750 errorCount += testUnknownPortGet ();
751 }
752 errorCount += testExternalGet ();
753 if (errorCount != 0)
754 fprintf (stderr, "Error (code: %u)\n", errorCount);
755 curl_global_cleanup ();
756 return errorCount != 0; /* 0 == pass */
757}