diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-10-17 11:53:21 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-10-17 11:53:21 +0300 |
commit | ec89305a37db6a39010b8311b8e7a8608621362d (patch) | |
tree | c7ce3286250e87ba48c7899b810fd1edc0bb8ec7 | |
parent | e2a49611e067feff63f51b2f4594f0bea01367f4 (diff) | |
download | libmicrohttpd-ec89305a37db6a39010b8311b8e7a8608621362d.tar.gz libmicrohttpd-ec89305a37db6a39010b8311b8e7a8608621362d.zip |
Added two tests with non-standard symbols in requests
-rw-r--r-- | src/testcurl/.gitignore | 2 | ||||
-rw-r--r-- | src/testcurl/Makefile.am | 9 | ||||
-rw-r--r-- | src/testcurl/test_tricky.c | 1158 |
3 files changed, 1169 insertions, 0 deletions
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore index 5f06c4fa..45b3fd0d 100644 --- a/src/testcurl/.gitignore +++ b/src/testcurl/.gitignore | |||
@@ -147,3 +147,5 @@ core | |||
147 | /test_toolarge_reply_header_name | 147 | /test_toolarge_reply_header_name |
148 | /test_toolarge_reply_header_value | 148 | /test_toolarge_reply_header_value |
149 | /test_toolarge_reply_headers | 149 | /test_toolarge_reply_headers |
150 | /test_tricky_url | ||
151 | /test_tricky_header2 \ No newline at end of file | ||
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am index f5b651c3..40a9fb13 100644 --- a/src/testcurl/Makefile.am +++ b/src/testcurl/Makefile.am | |||
@@ -107,6 +107,8 @@ check_PROGRAMS = \ | |||
107 | test_toolarge_reply_header_name \ | 107 | test_toolarge_reply_header_name \ |
108 | test_toolarge_reply_header_value \ | 108 | test_toolarge_reply_header_value \ |
109 | test_toolarge_reply_headers \ | 109 | test_toolarge_reply_headers \ |
110 | test_tricky_url \ | ||
111 | test_tricky_header2 \ | ||
110 | test_large_put \ | 112 | test_large_put \ |
111 | test_get11 \ | 113 | test_get11 \ |
112 | test_get_iovec11 \ | 114 | test_get_iovec11 \ |
@@ -455,3 +457,10 @@ test_toolarge_reply_header_value_SOURCES = \ | |||
455 | 457 | ||
456 | test_toolarge_reply_headers_SOURCES = \ | 458 | test_toolarge_reply_headers_SOURCES = \ |
457 | test_toolarge.c ../microhttpd/test_helpers.h | 459 | test_toolarge.c ../microhttpd/test_helpers.h |
460 | |||
461 | test_tricky_url_SOURCES = \ | ||
462 | test_tricky.c ../microhttpd/test_helpers.h | ||
463 | |||
464 | test_tricky_header2_SOURCES = \ | ||
465 | test_tricky.c ../microhttpd/test_helpers.h | ||
466 | \ No newline at end of file | ||
diff --git a/src/testcurl/test_tricky.c b/src/testcurl/test_tricky.c new file mode 100644 index 00000000..72b7485e --- /dev/null +++ b/src/testcurl/test_tricky.c | |||
@@ -0,0 +1,1158 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2014-2021 Evgeny Grin (Karlson2k) | ||
4 | Copyright (C) 2007, 2009, 2011 Christian Grothoff | ||
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 | * @file test_toolarge.c | ||
23 | * @brief Testcase for handling of untypical data. | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | * @author Christian Grothoff | ||
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 "test_helpers.h" | ||
35 | #include "mhd_sockets.h" /* only macros used */ | ||
36 | |||
37 | #ifdef HAVE_STRINGS_H | ||
38 | #include <strings.h> | ||
39 | #endif /* HAVE_STRINGS_H */ | ||
40 | |||
41 | #ifdef _WIN32 | ||
42 | #ifndef WIN32_LEAN_AND_MEAN | ||
43 | #define WIN32_LEAN_AND_MEAN 1 | ||
44 | #endif /* !WIN32_LEAN_AND_MEAN */ | ||
45 | #include <windows.h> | ||
46 | #endif | ||
47 | |||
48 | #ifndef WINDOWS | ||
49 | #include <unistd.h> | ||
50 | #include <sys/socket.h> | ||
51 | #endif | ||
52 | |||
53 | #ifdef HAVE_LIMITS_H | ||
54 | #include <limits.h> | ||
55 | #endif /* HAVE_LIMITS_H */ | ||
56 | |||
57 | #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 | ||
58 | #undef MHD_CPU_COUNT | ||
59 | #endif | ||
60 | #if ! defined(MHD_CPU_COUNT) | ||
61 | #define MHD_CPU_COUNT 2 | ||
62 | #endif | ||
63 | #if MHD_CPU_COUNT > 32 | ||
64 | #undef MHD_CPU_COUNT | ||
65 | /* Limit to reasonable value */ | ||
66 | #define MHD_CPU_COUNT 32 | ||
67 | #endif /* MHD_CPU_COUNT > 32 */ | ||
68 | |||
69 | |||
70 | #if defined(HAVE___FUNC__) | ||
71 | #define externalErrorExit(ignore) \ | ||
72 | _externalErrorExit_func(NULL, __func__, __LINE__) | ||
73 | #define externalErrorExitDesc(errDesc) \ | ||
74 | _externalErrorExit_func(errDesc, __func__, __LINE__) | ||
75 | #define libcurlErrorExit(ignore) \ | ||
76 | _libcurlErrorExit_func(NULL, __func__, __LINE__) | ||
77 | #define libcurlErrorExitDesc(errDesc) \ | ||
78 | _libcurlErrorExit_func(errDesc, __func__, __LINE__) | ||
79 | #define mhdErrorExit(ignore) \ | ||
80 | _mhdErrorExit_func(NULL, __func__, __LINE__) | ||
81 | #define mhdErrorExitDesc(errDesc) \ | ||
82 | _mhdErrorExit_func(errDesc, __func__, __LINE__) | ||
83 | #elif defined(HAVE___FUNCTION__) | ||
84 | #define externalErrorExit(ignore) \ | ||
85 | _externalErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
86 | #define externalErrorExitDesc(errDesc) \ | ||
87 | _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
88 | #define libcurlErrorExit(ignore) \ | ||
89 | _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
90 | #define libcurlErrorExitDesc(errDesc) \ | ||
91 | _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
92 | #define mhdErrorExit(ignore) \ | ||
93 | _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
94 | #define mhdErrorExitDesc(errDesc) \ | ||
95 | _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
96 | #else | ||
97 | #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) | ||
98 | #define externalErrorExitDesc(errDesc) \ | ||
99 | _externalErrorExit_func(errDesc, NULL, __LINE__) | ||
100 | #define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__) | ||
101 | #define libcurlErrorExitDesc(errDesc) \ | ||
102 | _libcurlErrorExit_func(errDesc, NULL, __LINE__) | ||
103 | #define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__) | ||
104 | #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__) | ||
105 | #endif | ||
106 | |||
107 | |||
108 | _MHD_NORETURN static void | ||
109 | _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
110 | { | ||
111 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
112 | fprintf (stderr, "%s", errDesc); | ||
113 | else | ||
114 | fprintf (stderr, "System or external library call failed"); | ||
115 | if ((NULL != funcName) && (0 != funcName[0])) | ||
116 | fprintf (stderr, " in %s", funcName); | ||
117 | if (0 < lineNum) | ||
118 | fprintf (stderr, " at line %d", lineNum); | ||
119 | |||
120 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
121 | strerror (errno)); | ||
122 | #ifdef MHD_WINSOCK_SOCKETS | ||
123 | fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); | ||
124 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
125 | fflush (stderr); | ||
126 | exit (99); | ||
127 | } | ||
128 | |||
129 | |||
130 | static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; | ||
131 | |||
132 | _MHD_NORETURN static void | ||
133 | _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
134 | { | ||
135 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
136 | fprintf (stderr, "%s", errDesc); | ||
137 | else | ||
138 | fprintf (stderr, "CURL library call failed"); | ||
139 | if ((NULL != funcName) && (0 != funcName[0])) | ||
140 | fprintf (stderr, " in %s", funcName); | ||
141 | if (0 < lineNum) | ||
142 | fprintf (stderr, " at line %d", lineNum); | ||
143 | |||
144 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
145 | strerror (errno)); | ||
146 | if (0 != libcurl_errbuf[0]) | ||
147 | fprintf (stderr, "Last libcurl error details: %s\n", libcurl_errbuf); | ||
148 | |||
149 | fflush (stderr); | ||
150 | exit (99); | ||
151 | } | ||
152 | |||
153 | |||
154 | _MHD_NORETURN static void | ||
155 | _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
156 | { | ||
157 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
158 | fprintf (stderr, "%s", errDesc); | ||
159 | else | ||
160 | fprintf (stderr, "MHD unexpected error"); | ||
161 | if ((NULL != funcName) && (0 != funcName[0])) | ||
162 | fprintf (stderr, " in %s", funcName); | ||
163 | if (0 < lineNum) | ||
164 | fprintf (stderr, " at line %d", lineNum); | ||
165 | |||
166 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
167 | strerror (errno)); | ||
168 | |||
169 | fflush (stderr); | ||
170 | exit (8); | ||
171 | } | ||
172 | |||
173 | |||
174 | /* Could be increased to facilitate debugging */ | ||
175 | #define TIMEOUTS_VAL 5 | ||
176 | |||
177 | #define EXPECTED_URI_BASE_PATH "/a" | ||
178 | |||
179 | #define EXPECTED_URI_BASE_PATH_TRICKY "/one\rtwo" | ||
180 | |||
181 | #define URL_SCHEME "http:/" "/" | ||
182 | |||
183 | #define URL_HOST "127.0.0.1" | ||
184 | |||
185 | #define URL_SCHEME_HOST URL_SCHEME URL_HOST | ||
186 | |||
187 | #define HEADER1_NAME "First" | ||
188 | #define HEADER1_VALUE "1st" | ||
189 | #define HEADER1 HEADER1_NAME ": " HEADER1_VALUE | ||
190 | #define HEADER2_NAME "Second" | ||
191 | #define HEADER2CR_VALUE "2\rnd" | ||
192 | #define HEADER2CR HEADER2_NAME ": " HEADER2CR_VALUE | ||
193 | /* Use headers when it would be properly supported by MHD | ||
194 | #define HEADER3CR_NAME "Thi\rrd" | ||
195 | #define HEADER3CR_VALUE "3r\rd" | ||
196 | #define HEADER3CR HEADER3CR_NAME ": " HEADER3CR_VALUE | ||
197 | */ | ||
198 | #define HEADER4_NAME "Normal" | ||
199 | #define HEADER4_VALUE "it's fine" | ||
200 | #define HEADER4 HEADER4_NAME ": " HEADER4_VALUE | ||
201 | |||
202 | /* Global parameters */ | ||
203 | static int verbose; /**< Be verbose */ | ||
204 | static int oneone; /**< If false use HTTP/1.0 for requests*/ | ||
205 | static int global_port; /**< MHD daemons listen port number */ | ||
206 | static int response_timeout_val = TIMEOUTS_VAL; | ||
207 | |||
208 | static int tricky_url; /**< Tricky request URL */ | ||
209 | static int tricky_header2; /**< Tricky request header2 */ | ||
210 | |||
211 | /* Current test parameters */ | ||
212 | /* * Moved to local variables * */ | ||
213 | |||
214 | /* Static helper variables */ | ||
215 | /* * None for this test * */ | ||
216 | |||
217 | static void | ||
218 | test_global_init (void) | ||
219 | { | ||
220 | libcurl_errbuf[0] = 0; | ||
221 | |||
222 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
223 | externalErrorExit (); | ||
224 | } | ||
225 | |||
226 | |||
227 | static void | ||
228 | test_global_cleanup (void) | ||
229 | { | ||
230 | curl_global_cleanup (); | ||
231 | } | ||
232 | |||
233 | |||
234 | struct headers_check_result | ||
235 | { | ||
236 | int dummy; /* no checks in this test */ | ||
237 | }; | ||
238 | |||
239 | |||
240 | size_t | ||
241 | lcurl_hdr_callback (char *buffer, size_t size, size_t nitems, | ||
242 | void *userdata) | ||
243 | { | ||
244 | const size_t data_size = size * nitems; | ||
245 | struct headers_check_result *check_res = | ||
246 | (struct headers_check_result *) userdata; | ||
247 | |||
248 | /* no checks in this test */ | ||
249 | (void) check_res; (void) buffer; | ||
250 | |||
251 | return data_size; | ||
252 | } | ||
253 | |||
254 | |||
255 | struct lcurl_data_cb_param | ||
256 | { | ||
257 | char *buf; | ||
258 | size_t pos; | ||
259 | size_t size; | ||
260 | }; | ||
261 | |||
262 | |||
263 | static size_t | ||
264 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
265 | { | ||
266 | struct lcurl_data_cb_param *cbc = ctx; | ||
267 | |||
268 | if (cbc->pos + size * nmemb > cbc->size) | ||
269 | externalErrorExit (); /* overflow */ | ||
270 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
271 | cbc->pos += size * nmemb; | ||
272 | return size * nmemb; | ||
273 | } | ||
274 | |||
275 | |||
276 | struct check_uri_cls | ||
277 | { | ||
278 | const char *volatile uri; | ||
279 | }; | ||
280 | |||
281 | static void * | ||
282 | check_uri_cb (void *cls, | ||
283 | const char *uri, | ||
284 | struct MHD_Connection *con) | ||
285 | { | ||
286 | struct check_uri_cls *param = (struct check_uri_cls *) cls; | ||
287 | (void) con; | ||
288 | |||
289 | if (0 != strcmp (param->uri, | ||
290 | uri)) | ||
291 | { | ||
292 | fprintf (stderr, | ||
293 | "Wrong URI: `%s', line: %d\n", | ||
294 | uri, __LINE__); | ||
295 | exit (22); | ||
296 | } | ||
297 | return NULL; | ||
298 | } | ||
299 | |||
300 | |||
301 | struct mhd_header_checker_param | ||
302 | { | ||
303 | int found_header1; | ||
304 | int found_header2; | ||
305 | int found_header4; | ||
306 | }; | ||
307 | |||
308 | enum MHD_Result | ||
309 | headerCheckerInterator (void *cls, | ||
310 | enum MHD_ValueKind kind, | ||
311 | const char *key, | ||
312 | size_t key_size, | ||
313 | const char *value, | ||
314 | size_t value_size) | ||
315 | { | ||
316 | struct mhd_header_checker_param *const param = | ||
317 | (struct mhd_header_checker_param *) cls; | ||
318 | |||
319 | if (NULL == param) | ||
320 | mhdErrorExitDesc ("cls parameter is NULL"); | ||
321 | |||
322 | if (MHD_HEADER_KIND != kind) | ||
323 | return MHD_YES; /* Continue iteration */ | ||
324 | |||
325 | if (0 == key_size) | ||
326 | mhdErrorExitDesc ("Zero key length"); | ||
327 | |||
328 | if ((strlen (HEADER1_NAME) == key_size) && | ||
329 | (0 == memcmp (key, HEADER1_NAME, key_size))) | ||
330 | { | ||
331 | if ((strlen (HEADER1_VALUE) == value_size) && | ||
332 | (0 == memcmp (value, HEADER1_VALUE, value_size))) | ||
333 | param->found_header1 = 1; | ||
334 | else | ||
335 | fprintf (stderr, "Unexpected header value: '%.*s', expected: '%s'\n", | ||
336 | (int) value_size, value, HEADER1_VALUE); | ||
337 | } | ||
338 | else if ((strlen (HEADER2_NAME) == key_size) && | ||
339 | (0 == memcmp (key, HEADER2_NAME, key_size))) | ||
340 | { | ||
341 | if ((strlen (HEADER2CR_VALUE) == value_size) && | ||
342 | (0 == memcmp (value, HEADER2CR_VALUE, value_size))) | ||
343 | param->found_header2 = 1; | ||
344 | else | ||
345 | fprintf (stderr, "Unexpected header value: '%.*s', expected: '%s'\n", | ||
346 | (int) value_size, value, HEADER2CR_VALUE); | ||
347 | } | ||
348 | else if ((strlen (HEADER4_NAME) == key_size) && | ||
349 | (0 == memcmp (key, HEADER4_NAME, key_size))) | ||
350 | { | ||
351 | if ((strlen (HEADER4_VALUE) == value_size) && | ||
352 | (0 == memcmp (value, HEADER4_VALUE, value_size))) | ||
353 | param->found_header4 = 1; | ||
354 | else | ||
355 | fprintf (stderr, "Unexpected header value: '%.*s', expected: '%s'\n", | ||
356 | (int) value_size, value, HEADER4_VALUE); | ||
357 | } | ||
358 | return MHD_YES; | ||
359 | } | ||
360 | |||
361 | |||
362 | struct ahc_cls_type | ||
363 | { | ||
364 | const char *volatile rp_data; | ||
365 | volatile size_t rp_data_size; | ||
366 | struct mhd_header_checker_param header_check_param; | ||
367 | const char *volatile rq_method; | ||
368 | const char *volatile rq_url; | ||
369 | }; | ||
370 | |||
371 | |||
372 | static enum MHD_Result | ||
373 | ahcCheck (void *cls, | ||
374 | struct MHD_Connection *connection, | ||
375 | const char *url, | ||
376 | const char *method, | ||
377 | const char *version, | ||
378 | const char *upload_data, size_t *upload_data_size, | ||
379 | void **con_cls) | ||
380 | { | ||
381 | static int ptr; | ||
382 | struct MHD_Response *response; | ||
383 | enum MHD_Result ret; | ||
384 | struct ahc_cls_type *const param = (struct ahc_cls_type *) cls; | ||
385 | |||
386 | if (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) | ||
387 | mhdErrorExitDesc ("Unexpected HTTP version"); | ||
388 | |||
389 | if (0 != strcmp (url, param->rq_url)) | ||
390 | mhdErrorExitDesc ("Unexpected URI"); | ||
391 | |||
392 | if (NULL != upload_data) | ||
393 | mhdErrorExitDesc ("'upload_data' is not NULL"); | ||
394 | |||
395 | if (NULL == upload_data_size) | ||
396 | mhdErrorExitDesc ("'upload_data_size' pointer is not NULL"); | ||
397 | |||
398 | if (0 != *upload_data_size) | ||
399 | mhdErrorExitDesc ("'*upload_data_size' value is not zero"); | ||
400 | |||
401 | if (NULL == param) | ||
402 | mhdErrorExitDesc ("cls parameter is NULL"); | ||
403 | |||
404 | if (0 != strcmp (param->rq_method, method)) | ||
405 | mhdErrorExitDesc ("Unexpected request method"); | ||
406 | |||
407 | if (&ptr != *con_cls) | ||
408 | { | ||
409 | *con_cls = &ptr; | ||
410 | return MHD_YES; | ||
411 | } | ||
412 | *con_cls = NULL; | ||
413 | |||
414 | if (1 > MHD_get_connection_values_n (connection, MHD_HEADER_KIND, | ||
415 | &headerCheckerInterator, | ||
416 | ¶m->header_check_param)) | ||
417 | mhdErrorExitDesc ("Wrong number of headers in the request"); | ||
418 | |||
419 | response = MHD_create_response_from_buffer (param->rp_data_size, | ||
420 | (void*) param->rp_data, | ||
421 | MHD_RESPMEM_MUST_COPY); | ||
422 | if (NULL == response) | ||
423 | mhdErrorExitDesc ("Failed to create response"); | ||
424 | |||
425 | ret = MHD_queue_response (connection, | ||
426 | MHD_HTTP_OK, | ||
427 | response); | ||
428 | MHD_destroy_response (response); | ||
429 | if (MHD_YES != ret) | ||
430 | mhdErrorExitDesc ("Failed to queue response"); | ||
431 | |||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | |||
436 | struct curlQueryParams | ||
437 | { | ||
438 | /* Destination path for CURL query */ | ||
439 | const char *queryPath; | ||
440 | |||
441 | #if CURL_AT_LEAST_VERSION (7, 62, 0) | ||
442 | CURLU *url; | ||
443 | #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */ | ||
444 | |||
445 | /* Custom query method, NULL for default */ | ||
446 | const char *method; | ||
447 | |||
448 | /* Destination port for CURL query */ | ||
449 | int queryPort; | ||
450 | |||
451 | /* List of additional request headers */ | ||
452 | struct curl_slist *headers; | ||
453 | |||
454 | /* CURL query result error flag */ | ||
455 | volatile int queryError; | ||
456 | |||
457 | /* Response HTTP code, zero if no response */ | ||
458 | volatile int responseCode; | ||
459 | }; | ||
460 | |||
461 | |||
462 | static CURL * | ||
463 | curlEasyInitForTest (struct curlQueryParams *p, | ||
464 | struct lcurl_data_cb_param *dcbp, | ||
465 | struct headers_check_result *hdr_chk_result) | ||
466 | { | ||
467 | CURL *c; | ||
468 | |||
469 | c = curl_easy_init (); | ||
470 | if (NULL == c) | ||
471 | libcurlErrorExitDesc ("curl_easy_init() failed"); | ||
472 | |||
473 | if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || | ||
474 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, p->queryPath)) || | ||
475 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) p->queryPort)) || | ||
476 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, | ||
477 | ©Buffer)) || | ||
478 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, dcbp)) || | ||
479 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, | ||
480 | (long) response_timeout_val)) || | ||
481 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, | ||
482 | (long) response_timeout_val)) || | ||
483 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, | ||
484 | libcurl_errbuf)) || | ||
485 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERFUNCTION, | ||
486 | lcurl_hdr_callback)) || | ||
487 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERDATA, | ||
488 | hdr_chk_result)) || | ||
489 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_PATH_AS_IS, | ||
490 | (long) 1)) || | ||
491 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || | ||
492 | (oneone) ? | ||
493 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, | ||
494 | CURL_HTTP_VERSION_1_1)) : | ||
495 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, | ||
496 | CURL_HTTP_VERSION_1_0))) | ||
497 | libcurlErrorExitDesc ("curl_easy_setopt() failed"); | ||
498 | |||
499 | if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, p->method)) | ||
500 | libcurlErrorExitDesc ("curl_easy_setopt() failed"); | ||
501 | |||
502 | if (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPHEADER, p->headers)) | ||
503 | libcurlErrorExitDesc ("curl_easy_setopt() failed"); | ||
504 | |||
505 | #if CURL_AT_LEAST_VERSION (7, 62, 0) | ||
506 | if (NULL != p->url) | ||
507 | { | ||
508 | if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CURLU, p->url)) | ||
509 | libcurlErrorExitDesc ("curl_easy_setopt() failed"); | ||
510 | } | ||
511 | #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */ | ||
512 | return c; | ||
513 | } | ||
514 | |||
515 | |||
516 | static CURLcode | ||
517 | performQueryExternal (struct MHD_Daemon *d, CURL *c) | ||
518 | { | ||
519 | CURLM *multi; | ||
520 | time_t start; | ||
521 | struct timeval tv; | ||
522 | CURLcode ret; | ||
523 | |||
524 | ret = CURLE_FAILED_INIT; /* will be replaced with real result */ | ||
525 | multi = NULL; | ||
526 | multi = curl_multi_init (); | ||
527 | if (multi == NULL) | ||
528 | libcurlErrorExitDesc ("curl_multi_init() failed"); | ||
529 | if (CURLM_OK != curl_multi_add_handle (multi, c)) | ||
530 | libcurlErrorExitDesc ("curl_multi_add_handle() failed"); | ||
531 | |||
532 | start = time (NULL); | ||
533 | while (time (NULL) - start <= TIMEOUTS_VAL) | ||
534 | { | ||
535 | fd_set rs; | ||
536 | fd_set ws; | ||
537 | fd_set es; | ||
538 | MHD_socket maxMhdSk; | ||
539 | int maxCurlSk; | ||
540 | int running; | ||
541 | |||
542 | maxMhdSk = MHD_INVALID_SOCKET; | ||
543 | maxCurlSk = -1; | ||
544 | FD_ZERO (&rs); | ||
545 | FD_ZERO (&ws); | ||
546 | FD_ZERO (&es); | ||
547 | if (NULL != multi) | ||
548 | { | ||
549 | curl_multi_perform (multi, &running); | ||
550 | if (0 == running) | ||
551 | { | ||
552 | struct CURLMsg *msg; | ||
553 | int msgLeft; | ||
554 | int totalMsgs = 0; | ||
555 | do | ||
556 | { | ||
557 | msg = curl_multi_info_read (multi, &msgLeft); | ||
558 | if (NULL == msg) | ||
559 | libcurlErrorExitDesc ("curl_multi_info_read() failed"); | ||
560 | totalMsgs++; | ||
561 | if (CURLMSG_DONE == msg->msg) | ||
562 | ret = msg->data.result; | ||
563 | } while (msgLeft > 0); | ||
564 | if (1 != totalMsgs) | ||
565 | { | ||
566 | fprintf (stderr, | ||
567 | "curl_multi_info_read returned wrong " | ||
568 | "number of results (%d).\n", | ||
569 | totalMsgs); | ||
570 | externalErrorExit (); | ||
571 | } | ||
572 | curl_multi_remove_handle (multi, c); | ||
573 | curl_multi_cleanup (multi); | ||
574 | multi = NULL; | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) | ||
579 | libcurlErrorExitDesc ("curl_multi_fdset() failed"); | ||
580 | } | ||
581 | } | ||
582 | if (NULL == multi) | ||
583 | { /* libcurl has finished, check whether MHD still needs to perform cleanup */ | ||
584 | unsigned long long to; | ||
585 | if ((MHD_YES != MHD_get_timeout (d, &to)) || (0 != to)) | ||
586 | break; /* MHD finished as well */ | ||
587 | } | ||
588 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) | ||
589 | mhdErrorExitDesc ("MHD_get_fdset() failed"); | ||
590 | tv.tv_sec = 0; | ||
591 | tv.tv_usec = 1000; | ||
592 | #ifdef MHD_POSIX_SOCKETS | ||
593 | if (maxMhdSk > maxCurlSk) | ||
594 | maxCurlSk = maxMhdSk; | ||
595 | #endif /* MHD_POSIX_SOCKETS */ | ||
596 | if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) | ||
597 | { | ||
598 | #ifdef MHD_POSIX_SOCKETS | ||
599 | if (EINTR != errno) | ||
600 | externalErrorExitDesc ("Unexpected select() error"); | ||
601 | #else | ||
602 | if ((WSAEINVAL != WSAGetLastError ()) || | ||
603 | (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) | ||
604 | externalErrorExitDesc ("Unexpected select() error"); | ||
605 | Sleep (1); | ||
606 | #endif | ||
607 | } | ||
608 | if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) | ||
609 | mhdErrorExitDesc ("MHD_run_from_select() failed"); | ||
610 | } | ||
611 | |||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | |||
616 | /* Returns zero for successful response and non-zero for failed response */ | ||
617 | static int | ||
618 | doCurlQueryInThread (struct MHD_Daemon *d, | ||
619 | struct curlQueryParams *p, | ||
620 | struct headers_check_result *hdr_res, | ||
621 | const char *expected_data, | ||
622 | size_t expected_data_size) | ||
623 | { | ||
624 | const union MHD_DaemonInfo *dinfo; | ||
625 | CURL *c; | ||
626 | struct lcurl_data_cb_param dcbp; | ||
627 | CURLcode errornum; | ||
628 | int use_external_poll; | ||
629 | long resp_code; | ||
630 | |||
631 | dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS); | ||
632 | if (NULL == dinfo) | ||
633 | mhdErrorExitDesc ("MHD_get_daemon_info() failed"); | ||
634 | use_external_poll = (0 == (dinfo->flags | ||
635 | & MHD_USE_INTERNAL_POLLING_THREAD)); | ||
636 | |||
637 | if (NULL == p->queryPath | ||
638 | #if CURL_AT_LEAST_VERSION (7, 62, 0) | ||
639 | && NULL == p->url | ||
640 | #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */ | ||
641 | ) | ||
642 | abort (); | ||
643 | |||
644 | if (0 == p->queryPort) | ||
645 | abort (); | ||
646 | |||
647 | /* Test must not fail due to test's internal buffer shortage */ | ||
648 | dcbp.size = expected_data_size * 2 + 1; | ||
649 | dcbp.buf = malloc (dcbp.size); | ||
650 | if (NULL == dcbp.buf) | ||
651 | externalErrorExit (); | ||
652 | dcbp.pos = 0; | ||
653 | |||
654 | memset (hdr_res, 0, sizeof(*hdr_res)); | ||
655 | |||
656 | c = curlEasyInitForTest (p, | ||
657 | &dcbp, hdr_res); | ||
658 | |||
659 | if (! use_external_poll) | ||
660 | errornum = curl_easy_perform (c); | ||
661 | else | ||
662 | errornum = performQueryExternal (d, c); | ||
663 | |||
664 | if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &resp_code)) | ||
665 | libcurlErrorExitDesc ("curl_easy_getinfo() failed"); | ||
666 | |||
667 | p->responseCode = (int) resp_code; | ||
668 | if ((CURLE_OK == errornum) && (200 != resp_code)) | ||
669 | { | ||
670 | fprintf (stderr, | ||
671 | "Got reply with unexpected status code: %d\n", | ||
672 | p->responseCode); | ||
673 | mhdErrorExit (); | ||
674 | } | ||
675 | |||
676 | if (CURLE_OK != errornum) | ||
677 | { | ||
678 | if ((CURLE_GOT_NOTHING != errornum) && (CURLE_RECV_ERROR != errornum) | ||
679 | && (CURLE_HTTP_RETURNED_ERROR != errornum)) | ||
680 | { | ||
681 | if (CURLE_OPERATION_TIMEDOUT == errornum) | ||
682 | mhdErrorExitDesc ("Request was aborted due to timeout"); | ||
683 | fprintf (stderr, "libcurl returned expected error: %s\n", | ||
684 | curl_easy_strerror (errornum)); | ||
685 | mhdErrorExitDesc ("Request failed due to unexpected error"); | ||
686 | } | ||
687 | p->queryError = 1; | ||
688 | if ((0 != resp_code) && | ||
689 | ((499 < resp_code) || (400 > resp_code))) /* TODO: add all expected error codes */ | ||
690 | { | ||
691 | fprintf (stderr, | ||
692 | "Got reply with unexpected status code: %ld\n", | ||
693 | resp_code); | ||
694 | mhdErrorExit (); | ||
695 | } | ||
696 | } | ||
697 | else | ||
698 | { | ||
699 | if (dcbp.pos != expected_data_size) | ||
700 | mhdErrorExit ("libcurl reports wrong size of MHD reply body data"); | ||
701 | else if (0 != memcmp (expected_data, dcbp.buf, | ||
702 | expected_data_size)) | ||
703 | mhdErrorExit ("libcurl reports wrong MHD reply body data"); | ||
704 | else | ||
705 | p->queryError = 0; | ||
706 | } | ||
707 | |||
708 | curl_easy_cleanup (c); | ||
709 | free (dcbp.buf); | ||
710 | |||
711 | return p->queryError; | ||
712 | } | ||
713 | |||
714 | |||
715 | /* Perform test queries, shut down MHD daemon, and free parameters */ | ||
716 | static int | ||
717 | performTestQueries (struct MHD_Daemon *d, int d_port, | ||
718 | struct ahc_cls_type *ahc_param, | ||
719 | struct check_uri_cls *uri_cb_param) | ||
720 | { | ||
721 | struct curlQueryParams qParam; | ||
722 | int ret = 0; /* Return value */ | ||
723 | struct headers_check_result rp_headers_check; | ||
724 | struct curl_slist *curl_headers; | ||
725 | curl_headers = NULL; | ||
726 | |||
727 | /* Common parameters, to be individually overridden by specific test cases */ | ||
728 | qParam.queryPort = d_port; | ||
729 | qParam.method = NULL; /* Use libcurl default: GET */ | ||
730 | qParam.queryPath = URL_SCHEME_HOST EXPECTED_URI_BASE_PATH; | ||
731 | #if CURL_AT_LEAST_VERSION (7, 62, 0) | ||
732 | qParam.url = NULL; | ||
733 | #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */ | ||
734 | qParam.headers = NULL; /* No additional headers */ | ||
735 | uri_cb_param->uri = EXPECTED_URI_BASE_PATH; | ||
736 | ahc_param->rq_url = EXPECTED_URI_BASE_PATH; | ||
737 | ahc_param->rq_method = "GET"; /* Default expected method */ | ||
738 | |||
739 | ahc_param->rp_data = "~"; | ||
740 | ahc_param->rp_data_size = 1; | ||
741 | |||
742 | curl_headers = curl_slist_append (curl_headers, HEADER1); | ||
743 | if (NULL == curl_headers) | ||
744 | externalErrorExit (); | ||
745 | curl_headers = curl_slist_append (curl_headers, HEADER4); | ||
746 | if (NULL == curl_headers) | ||
747 | externalErrorExit (); | ||
748 | qParam.headers = curl_headers; | ||
749 | |||
750 | memset (&ahc_param->header_check_param, 0, | ||
751 | sizeof (ahc_param->header_check_param)); | ||
752 | |||
753 | if (tricky_url) | ||
754 | { | ||
755 | #if CURL_AT_LEAST_VERSION (7, 62, 0) | ||
756 | qParam.url = curl_url (); | ||
757 | if (NULL == qParam.url) | ||
758 | externalErrorExit (); | ||
759 | |||
760 | if ((CURLUE_OK != curl_url_set (qParam.url, CURLUPART_SCHEME, "http", 0)) || | ||
761 | (CURLUE_OK != curl_url_set (qParam.url, CURLUPART_HOST, URL_HOST, | ||
762 | CURLU_PATH_AS_IS | CURLU_ALLOW_SPACE)) || | ||
763 | (CURLUE_OK != curl_url_set (qParam.url, CURLUPART_PATH, | ||
764 | EXPECTED_URI_BASE_PATH_TRICKY, 0))) | ||
765 | libcurlErrorExit (); | ||
766 | |||
767 | qParam.queryPath = NULL; | ||
768 | uri_cb_param->uri = EXPECTED_URI_BASE_PATH_TRICKY; | ||
769 | ahc_param->rq_url = EXPECTED_URI_BASE_PATH_TRICKY; | ||
770 | |||
771 | if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, | ||
772 | ahc_param->rp_data, | ||
773 | ahc_param->rp_data_size)) | ||
774 | { | ||
775 | /* TODO: Allow fail only if relevant MHD mode set */ | ||
776 | if (0 == qParam.responseCode) | ||
777 | { | ||
778 | fprintf (stderr, "Request failed without any valid response.\n"); | ||
779 | ret = 1; | ||
780 | } | ||
781 | else | ||
782 | { | ||
783 | if (verbose) | ||
784 | printf ("Request failed with %d response code.\n", | ||
785 | qParam.responseCode); | ||
786 | (void) qParam.responseCode; /* TODO: check for the right response code */ | ||
787 | ret = 0; | ||
788 | } | ||
789 | } | ||
790 | else | ||
791 | { | ||
792 | if (200 != qParam.responseCode) | ||
793 | { | ||
794 | fprintf (stderr, "Request succeed with wrong response code: %d.\n", | ||
795 | qParam.responseCode); | ||
796 | ret = 1; | ||
797 | } | ||
798 | else | ||
799 | { | ||
800 | ret = 0; | ||
801 | if (verbose) | ||
802 | printf ("Request succeed.\n"); | ||
803 | } | ||
804 | |||
805 | if (! ahc_param->header_check_param.found_header1) | ||
806 | mhdErrorExitDesc ("Required header1 was not detected in request"); | ||
807 | if (! ahc_param->header_check_param.found_header4) | ||
808 | mhdErrorExitDesc ("Required header4 was not detected in request"); | ||
809 | } | ||
810 | |||
811 | #else | ||
812 | fprintf ("This test requires libcurl version 7.62.0 or newer.\n"); | ||
813 | abort (); | ||
814 | #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */ | ||
815 | } | ||
816 | else if (tricky_header2) | ||
817 | { | ||
818 | /* Reset libcurl headers */ | ||
819 | qParam.headers = NULL; | ||
820 | curl_slist_free_all (curl_headers); | ||
821 | curl_headers = NULL; | ||
822 | |||
823 | /* Set special libcurl headers */ | ||
824 | curl_headers = curl_slist_append (curl_headers, HEADER1); | ||
825 | if (NULL == curl_headers) | ||
826 | externalErrorExit (); | ||
827 | curl_headers = curl_slist_append (curl_headers, HEADER2CR); | ||
828 | if (NULL == curl_headers) | ||
829 | externalErrorExit (); | ||
830 | curl_headers = curl_slist_append (curl_headers, HEADER4); | ||
831 | if (NULL == curl_headers) | ||
832 | externalErrorExit (); | ||
833 | qParam.headers = curl_headers; | ||
834 | |||
835 | if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, | ||
836 | ahc_param->rp_data, | ||
837 | ahc_param->rp_data_size)) | ||
838 | { | ||
839 | /* TODO: Allow fail only if relevant MHD mode set */ | ||
840 | if (0 == qParam.responseCode) | ||
841 | { | ||
842 | fprintf (stderr, "Request failed without any valid response.\n"); | ||
843 | ret = 1; | ||
844 | } | ||
845 | else | ||
846 | { | ||
847 | if (verbose) | ||
848 | printf ("Request failed with %d response code.\n", | ||
849 | qParam.responseCode); | ||
850 | (void) qParam.responseCode; /* TODO: check for the right response code */ | ||
851 | ret = 0; | ||
852 | } | ||
853 | } | ||
854 | else | ||
855 | { | ||
856 | if (200 != qParam.responseCode) | ||
857 | { | ||
858 | fprintf (stderr, "Request succeed with wrong response code: %d.\n", | ||
859 | qParam.responseCode); | ||
860 | ret = 1; | ||
861 | } | ||
862 | else | ||
863 | { | ||
864 | ret = 0; | ||
865 | if (verbose) | ||
866 | printf ("Request succeed.\n"); | ||
867 | } | ||
868 | |||
869 | if (! ahc_param->header_check_param.found_header1) | ||
870 | mhdErrorExitDesc ("Required header1 was not detected in request"); | ||
871 | if (! ahc_param->header_check_param.found_header2) | ||
872 | mhdErrorExitDesc ("Required header2 was not detected in request"); | ||
873 | if (! ahc_param->header_check_param.found_header4) | ||
874 | mhdErrorExitDesc ("Required header4 was not detected in request"); | ||
875 | } | ||
876 | } | ||
877 | else | ||
878 | externalErrorExitDesc ("No valid test test was selected"); | ||
879 | |||
880 | MHD_stop_daemon (d); | ||
881 | curl_slist_free_all (curl_headers); | ||
882 | free (uri_cb_param); | ||
883 | free (ahc_param); | ||
884 | |||
885 | return ret; | ||
886 | } | ||
887 | |||
888 | |||
889 | enum testMhdThreadsType | ||
890 | { | ||
891 | testMhdThreadExternal = 0, | ||
892 | testMhdThreadInternal = MHD_USE_INTERNAL_POLLING_THREAD, | ||
893 | testMhdThreadInternalPerConnection = MHD_USE_THREAD_PER_CONNECTION | ||
894 | | MHD_USE_INTERNAL_POLLING_THREAD, | ||
895 | testMhdThreadInternalPool | ||
896 | }; | ||
897 | |||
898 | enum testMhdPollType | ||
899 | { | ||
900 | testMhdPollBySelect = 0, | ||
901 | testMhdPollByPoll = MHD_USE_POLL, | ||
902 | testMhdPollByEpoll = MHD_USE_EPOLL, | ||
903 | testMhdPollAuto = MHD_USE_AUTO | ||
904 | }; | ||
905 | |||
906 | /* Get number of threads for thread pool depending | ||
907 | * on used poll function and test type. */ | ||
908 | static unsigned int | ||
909 | testNumThreadsForPool (enum testMhdPollType pollType) | ||
910 | { | ||
911 | int numThreads = MHD_CPU_COUNT; | ||
912 | (void) pollType; /* Don't care about pollType for this test */ | ||
913 | return numThreads; /* No practical limit for non-cleanup test */ | ||
914 | } | ||
915 | |||
916 | |||
917 | static struct MHD_Daemon * | ||
918 | startTestMhdDaemon (enum testMhdThreadsType thrType, | ||
919 | enum testMhdPollType pollType, int *pport, | ||
920 | struct ahc_cls_type **ahc_param, | ||
921 | struct check_uri_cls **uri_cb_param) | ||
922 | { | ||
923 | struct MHD_Daemon *d; | ||
924 | const union MHD_DaemonInfo *dinfo; | ||
925 | |||
926 | if ((NULL == ahc_param) || (NULL == uri_cb_param)) | ||
927 | abort (); | ||
928 | |||
929 | *ahc_param = (struct ahc_cls_type *) malloc (sizeof(struct ahc_cls_type)); | ||
930 | if (NULL == *ahc_param) | ||
931 | externalErrorExit (); | ||
932 | *uri_cb_param = | ||
933 | (struct check_uri_cls *) malloc (sizeof(struct check_uri_cls)); | ||
934 | if (NULL == *uri_cb_param) | ||
935 | externalErrorExit (); | ||
936 | |||
937 | if ( (0 == *pport) && | ||
938 | (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) | ||
939 | { | ||
940 | *pport = 4150; | ||
941 | if (tricky_url) | ||
942 | *pport += 1; | ||
943 | if (tricky_header2) | ||
944 | *pport += 2; | ||
945 | if (! oneone) | ||
946 | *pport += 16; | ||
947 | } | ||
948 | |||
949 | if (testMhdThreadInternalPool != thrType) | ||
950 | d = MHD_start_daemon (((int) thrType) | ((int) pollType) | ||
951 | | (verbose ? MHD_USE_ERROR_LOG : 0), | ||
952 | *pport, NULL, NULL, | ||
953 | &ahcCheck, *ahc_param, | ||
954 | MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb, | ||
955 | *uri_cb_param, | ||
956 | MHD_OPTION_END); | ||
957 | else | ||
958 | d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | ((int) pollType) | ||
959 | | (verbose ? MHD_USE_ERROR_LOG : 0), | ||
960 | *pport, NULL, NULL, | ||
961 | &ahcCheck, *ahc_param, | ||
962 | MHD_OPTION_THREAD_POOL_SIZE, | ||
963 | testNumThreadsForPool (pollType), | ||
964 | MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb, | ||
965 | *uri_cb_param, | ||
966 | MHD_OPTION_END); | ||
967 | |||
968 | if (NULL == d) | ||
969 | { | ||
970 | fprintf (stderr, "Failed to start MHD daemon, errno=%d.\n", errno); | ||
971 | abort (); | ||
972 | } | ||
973 | |||
974 | if (0 == *pport) | ||
975 | { | ||
976 | dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); | ||
977 | if ((NULL == dinfo) || (0 == dinfo->port) ) | ||
978 | { | ||
979 | fprintf (stderr, "MHD_get_daemon_info() failed.\n"); | ||
980 | abort (); | ||
981 | } | ||
982 | *pport = (int) dinfo->port; | ||
983 | if (0 == global_port) | ||
984 | global_port = *pport; /* Reuse the same port for all tests */ | ||
985 | } | ||
986 | |||
987 | return d; | ||
988 | } | ||
989 | |||
990 | |||
991 | /* Test runners */ | ||
992 | |||
993 | |||
994 | static int | ||
995 | testExternalGet (void) | ||
996 | { | ||
997 | struct MHD_Daemon *d; | ||
998 | int d_port = global_port; /* Daemon's port */ | ||
999 | struct ahc_cls_type *ahc_param; | ||
1000 | struct check_uri_cls *uri_cb_param; | ||
1001 | |||
1002 | d = startTestMhdDaemon (testMhdThreadExternal, testMhdPollBySelect, &d_port, | ||
1003 | &ahc_param, &uri_cb_param); | ||
1004 | |||
1005 | return performTestQueries (d, d_port, ahc_param, uri_cb_param); | ||
1006 | } | ||
1007 | |||
1008 | |||
1009 | static int | ||
1010 | testInternalGet (enum testMhdPollType pollType) | ||
1011 | { | ||
1012 | struct MHD_Daemon *d; | ||
1013 | int d_port = global_port; /* Daemon's port */ | ||
1014 | struct ahc_cls_type *ahc_param; | ||
1015 | struct check_uri_cls *uri_cb_param; | ||
1016 | |||
1017 | d = startTestMhdDaemon (testMhdThreadInternal, pollType, &d_port, | ||
1018 | &ahc_param, &uri_cb_param); | ||
1019 | |||
1020 | return performTestQueries (d, d_port, ahc_param, uri_cb_param); | ||
1021 | } | ||
1022 | |||
1023 | |||
1024 | static int | ||
1025 | testMultithreadedGet (enum testMhdPollType pollType) | ||
1026 | { | ||
1027 | struct MHD_Daemon *d; | ||
1028 | int d_port = global_port; /* Daemon's port */ | ||
1029 | struct ahc_cls_type *ahc_param; | ||
1030 | struct check_uri_cls *uri_cb_param; | ||
1031 | |||
1032 | d = startTestMhdDaemon (testMhdThreadInternalPerConnection, pollType, &d_port, | ||
1033 | &ahc_param, &uri_cb_param); | ||
1034 | return performTestQueries (d, d_port, ahc_param, uri_cb_param); | ||
1035 | } | ||
1036 | |||
1037 | |||
1038 | static int | ||
1039 | testMultithreadedPoolGet (enum testMhdPollType pollType) | ||
1040 | { | ||
1041 | struct MHD_Daemon *d; | ||
1042 | int d_port = global_port; /* Daemon's port */ | ||
1043 | struct ahc_cls_type *ahc_param; | ||
1044 | struct check_uri_cls *uri_cb_param; | ||
1045 | |||
1046 | d = startTestMhdDaemon (testMhdThreadInternalPool, pollType, &d_port, | ||
1047 | &ahc_param, &uri_cb_param); | ||
1048 | return performTestQueries (d, d_port, ahc_param, uri_cb_param); | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | int | ||
1053 | main (int argc, char *const *argv) | ||
1054 | { | ||
1055 | unsigned int errorCount = 0; | ||
1056 | unsigned int test_result = 0; | ||
1057 | verbose = 0; | ||
1058 | |||
1059 | if ((NULL == argv) || (0 == argv[0])) | ||
1060 | return 99; | ||
1061 | oneone = ! has_in_name (argv[0], "10"); | ||
1062 | tricky_url = has_in_name (argv[0], "_url") ? 1 : 0; | ||
1063 | tricky_header2 = has_in_name (argv[0], "_header2") ? 1 : 0; | ||
1064 | if (1 != tricky_url + tricky_header2) | ||
1065 | return 99; | ||
1066 | verbose = ! has_param (argc, argv, "-q") || has_param (argc, argv, "--quiet"); | ||
1067 | |||
1068 | #if ! CURL_AT_LEAST_VERSION (7, 62, 0) | ||
1069 | if (tricky_url) | ||
1070 | { | ||
1071 | fprintf ("This test requires libcurl version 7.62.0 or newer.\n"); | ||
1072 | return 77; | ||
1073 | } | ||
1074 | #endif /* ! CURL_AT_LEAST_VERSION(7, 62, 0) */ | ||
1075 | |||
1076 | test_global_init (); | ||
1077 | |||
1078 | /* Could be set to non-zero value to enforce using specific port | ||
1079 | * in the test */ | ||
1080 | global_port = 0; | ||
1081 | test_result = testExternalGet (); | ||
1082 | if (test_result) | ||
1083 | fprintf (stderr, "FAILED: testExternalGet () - %u.\n", test_result); | ||
1084 | else if (verbose) | ||
1085 | printf ("PASSED: testExternalGet ().\n"); | ||
1086 | errorCount += test_result; | ||
1087 | if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) | ||
1088 | { | ||
1089 | test_result = testInternalGet (testMhdPollAuto); | ||
1090 | if (test_result) | ||
1091 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollAuto) - %u.\n", | ||
1092 | test_result); | ||
1093 | else if (verbose) | ||
1094 | printf ("PASSED: testInternalGet (testMhdPollBySelect).\n"); | ||
1095 | errorCount += test_result; | ||
1096 | #ifdef _MHD_HEAVY_TESTS | ||
1097 | /* Actually tests are not heavy, but took too long to complete while | ||
1098 | * not really provide any additional results. */ | ||
1099 | test_result = testInternalGet (testMhdPollBySelect); | ||
1100 | if (test_result) | ||
1101 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollBySelect) - %u.\n", | ||
1102 | test_result); | ||
1103 | else if (verbose) | ||
1104 | printf ("PASSED: testInternalGet (testMhdPollBySelect).\n"); | ||
1105 | errorCount += test_result; | ||
1106 | test_result = testMultithreadedPoolGet (testMhdPollBySelect); | ||
1107 | if (test_result) | ||
1108 | fprintf (stderr, | ||
1109 | "FAILED: testMultithreadedPoolGet (testMhdPollBySelect) - %u.\n", | ||
1110 | test_result); | ||
1111 | else if (verbose) | ||
1112 | printf ("PASSED: testMultithreadedPoolGet (testMhdPollBySelect).\n"); | ||
1113 | errorCount += test_result; | ||
1114 | test_result = testMultithreadedGet (testMhdPollBySelect); | ||
1115 | if (test_result) | ||
1116 | fprintf (stderr, | ||
1117 | "FAILED: testMultithreadedGet (testMhdPollBySelect) - %u.\n", | ||
1118 | test_result); | ||
1119 | else if (verbose) | ||
1120 | printf ("PASSED: testMultithreadedGet (testMhdPollBySelect).\n"); | ||
1121 | errorCount += test_result; | ||
1122 | if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL)) | ||
1123 | { | ||
1124 | test_result = testInternalGet (testMhdPollByPoll); | ||
1125 | if (test_result) | ||
1126 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollByPoll) - %u.\n", | ||
1127 | test_result); | ||
1128 | else if (verbose) | ||
1129 | printf ("PASSED: testInternalGet (testMhdPollByPoll).\n"); | ||
1130 | errorCount += test_result; | ||
1131 | } | ||
1132 | if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL)) | ||
1133 | { | ||
1134 | test_result = testInternalGet (testMhdPollByEpoll); | ||
1135 | if (test_result) | ||
1136 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollByEpoll) - %u.\n", | ||
1137 | test_result); | ||
1138 | else if (verbose) | ||
1139 | printf ("PASSED: testInternalGet (testMhdPollByEpoll).\n"); | ||
1140 | errorCount += test_result; | ||
1141 | } | ||
1142 | #else | ||
1143 | /* Mute compiler warnings */ | ||
1144 | (void) testMultithreadedGet; | ||
1145 | (void) testMultithreadedPoolGet; | ||
1146 | #endif /* _MHD_HEAVY_TESTS */ | ||
1147 | } | ||
1148 | if (0 != errorCount) | ||
1149 | fprintf (stderr, | ||
1150 | "Error (code: %u)\n", | ||
1151 | errorCount); | ||
1152 | else if (verbose) | ||
1153 | printf ("All tests passed.\n"); | ||
1154 | |||
1155 | test_global_cleanup (); | ||
1156 | |||
1157 | return (errorCount == 0) ? 0 : 1; /* 0 == pass */ | ||
1158 | } | ||