diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-05-28 19:42:14 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-05-28 19:54:44 +0300 |
commit | 435cd008a8c1caee536f539283aa59adf25d94a6 (patch) | |
tree | 6699994728ab6dbd9f02168357f70a9955b06076 /src/testcurl | |
parent | d73c6d20e301775597feea322416e475262a9558 (diff) | |
download | libmicrohttpd-435cd008a8c1caee536f539283aa59adf25d94a6.tar.gz libmicrohttpd-435cd008a8c1caee536f539283aa59adf25d94a6.zip |
test_basicauth: added new test
Diffstat (limited to 'src/testcurl')
-rw-r--r-- | src/testcurl/Makefile.am | 8 | ||||
-rw-r--r-- | src/testcurl/test_basicauth.c | 636 |
2 files changed, 644 insertions, 0 deletions
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am index 4b0c3d1c..ed585527 100644 --- a/src/testcurl/Makefile.am +++ b/src/testcurl/Makefile.am | |||
@@ -151,6 +151,11 @@ check_PROGRAMS += \ | |||
151 | perf_get | 151 | perf_get |
152 | endif | 152 | endif |
153 | 153 | ||
154 | if ENABLE_BAUTH | ||
155 | check_PROGRAMS += \ | ||
156 | test_basicauth | ||
157 | endif | ||
158 | |||
154 | if HAVE_POSTPROCESSOR | 159 | if HAVE_POSTPROCESSOR |
155 | check_PROGRAMS += \ | 160 | check_PROGRAMS += \ |
156 | test_post \ | 161 | test_post \ |
@@ -228,6 +233,9 @@ perf_get_concurrent11_CFLAGS = \ | |||
228 | perf_get_concurrent11_LDADD = \ | 233 | perf_get_concurrent11_LDADD = \ |
229 | $(PTHREAD_LIBS) $(LDADD) | 234 | $(PTHREAD_LIBS) $(LDADD) |
230 | 235 | ||
236 | test_basicauth_SOURCES = \ | ||
237 | test_basicauth.c | ||
238 | |||
231 | test_digestauth_SOURCES = \ | 239 | test_digestauth_SOURCES = \ |
232 | test_digestauth.c | 240 | test_digestauth.c |
233 | test_digestauth_LDADD = \ | 241 | test_digestauth_LDADD = \ |
diff --git a/src/testcurl/test_basicauth.c b/src/testcurl/test_basicauth.c new file mode 100644 index 00000000..1b84ac15 --- /dev/null +++ b/src/testcurl/test_basicauth.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2010 Christian Grothoff | ||
4 | Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) | ||
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_basicauth.c | ||
24 | * @brief Testcase for libmicrohttpd concurrent Basic Authorisation | ||
25 | * @author Amr Ali | ||
26 | * @author Karlson2k (Evgeny Grin) | ||
27 | */ | ||
28 | |||
29 | #include "MHD_config.h" | ||
30 | #include "platform.h" | ||
31 | #include <curl/curl.h> | ||
32 | #include <microhttpd.h> | ||
33 | #include <stdlib.h> | ||
34 | #include <string.h> | ||
35 | #include <time.h> | ||
36 | |||
37 | #ifndef WINDOWS | ||
38 | #include <sys/socket.h> | ||
39 | #include <unistd.h> | ||
40 | #else | ||
41 | #include <wincrypt.h> | ||
42 | #endif | ||
43 | |||
44 | #include "mhd_has_param.h" | ||
45 | |||
46 | #ifndef MHD_STATICSTR_LEN_ | ||
47 | /** | ||
48 | * Determine length of static string / macro strings at compile time. | ||
49 | */ | ||
50 | #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) | ||
51 | #endif /* ! MHD_STATICSTR_LEN_ */ | ||
52 | |||
53 | #ifndef CURL_VERSION_BITS | ||
54 | #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) | ||
55 | #endif /* ! CURL_VERSION_BITS */ | ||
56 | #ifndef CURL_AT_LEAST_VERSION | ||
57 | #define CURL_AT_LEAST_VERSION(x,y,z) \ | ||
58 | (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) | ||
59 | #endif /* ! CURL_AT_LEAST_VERSION */ | ||
60 | |||
61 | #ifndef _MHD_INSTRMACRO | ||
62 | /* Quoted macro parameter */ | ||
63 | #define _MHD_INSTRMACRO(a) #a | ||
64 | #endif /* ! _MHD_INSTRMACRO */ | ||
65 | #ifndef _MHD_STRMACRO | ||
66 | /* Quoted expanded macro parameter */ | ||
67 | #define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a) | ||
68 | #endif /* ! _MHD_STRMACRO */ | ||
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 | #define checkCURLE_OK(libcurlcall) \ | ||
84 | _checkCURLE_OK_func((libcurlcall), _MHD_STRMACRO(libcurlcall), \ | ||
85 | __func__, __LINE__) | ||
86 | #elif defined(HAVE___FUNCTION__) | ||
87 | #define externalErrorExit(ignore) \ | ||
88 | _externalErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
89 | #define externalErrorExitDesc(errDesc) \ | ||
90 | _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
91 | #define libcurlErrorExit(ignore) \ | ||
92 | _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
93 | #define libcurlErrorExitDesc(errDesc) \ | ||
94 | _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
95 | #define mhdErrorExit(ignore) \ | ||
96 | _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
97 | #define mhdErrorExitDesc(errDesc) \ | ||
98 | _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
99 | #define checkCURLE_OK(libcurlcall) \ | ||
100 | _checkCURLE_OK_func((libcurlcall), _MHD_STRMACRO(libcurlcall), \ | ||
101 | __FUNCTION__, __LINE__) | ||
102 | #else | ||
103 | #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) | ||
104 | #define externalErrorExitDesc(errDesc) \ | ||
105 | _externalErrorExit_func(errDesc, NULL, __LINE__) | ||
106 | #define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__) | ||
107 | #define libcurlErrorExitDesc(errDesc) \ | ||
108 | _libcurlErrorExit_func(errDesc, NULL, __LINE__) | ||
109 | #define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__) | ||
110 | #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__) | ||
111 | #define checkCURLE_OK(libcurlcall) \ | ||
112 | _checkCURLE_OK_func((libcurlcall), _MHD_STRMACRO(libcurlcall), NULL, __LINE__) | ||
113 | #endif | ||
114 | |||
115 | |||
116 | _MHD_NORETURN static void | ||
117 | _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
118 | { | ||
119 | fflush (stdout); | ||
120 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
121 | fprintf (stderr, "%s", errDesc); | ||
122 | else | ||
123 | fprintf (stderr, "System or external library call failed"); | ||
124 | if ((NULL != funcName) && (0 != funcName[0])) | ||
125 | fprintf (stderr, " in %s", funcName); | ||
126 | if (0 < lineNum) | ||
127 | fprintf (stderr, " at line %d", lineNum); | ||
128 | |||
129 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
130 | strerror (errno)); | ||
131 | #ifdef MHD_WINSOCK_SOCKETS | ||
132 | fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); | ||
133 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
134 | fflush (stderr); | ||
135 | exit (99); | ||
136 | } | ||
137 | |||
138 | |||
139 | /* Not actually used in this test */ | ||
140 | static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; | ||
141 | |||
142 | _MHD_NORETURN static void | ||
143 | _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
144 | { | ||
145 | fflush (stdout); | ||
146 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
147 | fprintf (stderr, "%s", errDesc); | ||
148 | else | ||
149 | fprintf (stderr, "CURL library call failed"); | ||
150 | if ((NULL != funcName) && (0 != funcName[0])) | ||
151 | fprintf (stderr, " in %s", funcName); | ||
152 | if (0 < lineNum) | ||
153 | fprintf (stderr, " at line %d", lineNum); | ||
154 | |||
155 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
156 | strerror (errno)); | ||
157 | #ifdef MHD_WINSOCK_SOCKETS | ||
158 | fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); | ||
159 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
160 | if (0 != libcurl_errbuf[0]) | ||
161 | fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); | ||
162 | |||
163 | fflush (stderr); | ||
164 | exit (99); | ||
165 | } | ||
166 | |||
167 | |||
168 | _MHD_NORETURN static void | ||
169 | _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
170 | { | ||
171 | fflush (stdout); | ||
172 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
173 | fprintf (stderr, "%s", errDesc); | ||
174 | else | ||
175 | fprintf (stderr, "MHD unexpected error"); | ||
176 | if ((NULL != funcName) && (0 != funcName[0])) | ||
177 | fprintf (stderr, " in %s", funcName); | ||
178 | if (0 < lineNum) | ||
179 | fprintf (stderr, " at line %d", lineNum); | ||
180 | |||
181 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
182 | strerror (errno)); | ||
183 | #ifdef MHD_WINSOCK_SOCKETS | ||
184 | fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); | ||
185 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
186 | |||
187 | fflush (stderr); | ||
188 | exit (8); | ||
189 | } | ||
190 | |||
191 | |||
192 | #if 0 | ||
193 | /* Function unused in this test */ | ||
194 | static void | ||
195 | _checkCURLE_OK_func (CURLcode code, const char *curlFunc, | ||
196 | const char *funcName, int lineNum) | ||
197 | { | ||
198 | if (CURLE_OK == code) | ||
199 | return; | ||
200 | |||
201 | fflush (stdout); | ||
202 | if ((NULL != curlFunc) && (0 != curlFunc[0])) | ||
203 | fprintf (stderr, "'%s' resulted in '%s'", curlFunc, | ||
204 | curl_easy_strerror (code)); | ||
205 | else | ||
206 | fprintf (stderr, "libcurl function call resulted in '%s'", | ||
207 | curl_easy_strerror (code)); | ||
208 | if ((NULL != funcName) && (0 != funcName[0])) | ||
209 | fprintf (stderr, " in %s", funcName); | ||
210 | if (0 < lineNum) | ||
211 | fprintf (stderr, " at line %d", lineNum); | ||
212 | |||
213 | fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, | ||
214 | strerror (errno)); | ||
215 | if (0 != libcurl_errbuf[0]) | ||
216 | fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); | ||
217 | |||
218 | fflush (stderr); | ||
219 | exit (9); | ||
220 | } | ||
221 | |||
222 | |||
223 | #endif | ||
224 | |||
225 | |||
226 | /* Could be increased to facilitate debugging */ | ||
227 | #define TIMEOUTS_VAL 10 | ||
228 | |||
229 | #define MHD_URI_BASE_PATH "/bar%20foo%3Fkey%3Dvalue" | ||
230 | |||
231 | #define REALM "TestRealm" | ||
232 | #define USERNAME "Aladdin" | ||
233 | #define PASSWORD "open sesame" | ||
234 | |||
235 | |||
236 | #define PAGE \ | ||
237 | "<html><head><title>libmicrohttpd demo page</title>" \ | ||
238 | "</head><body>Access granted</body></html>" | ||
239 | |||
240 | #define DENIED \ | ||
241 | "<html><head><title>libmicrohttpd - Access denied</title>" \ | ||
242 | "</head><body>Access denied</body></html>" | ||
243 | |||
244 | struct CBC | ||
245 | { | ||
246 | char *buf; | ||
247 | size_t pos; | ||
248 | size_t size; | ||
249 | }; | ||
250 | |||
251 | static int verbose; | ||
252 | |||
253 | static size_t | ||
254 | copyBuffer (void *ptr, | ||
255 | size_t size, | ||
256 | size_t nmemb, | ||
257 | void *ctx) | ||
258 | { | ||
259 | struct CBC *cbc = ctx; | ||
260 | |||
261 | if (cbc->pos + size * nmemb > cbc->size) | ||
262 | mhdErrorExitDesc ("Wrong too large data"); /* overflow */ | ||
263 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
264 | cbc->pos += size * nmemb; | ||
265 | return size * nmemb; | ||
266 | } | ||
267 | |||
268 | |||
269 | static enum MHD_Result | ||
270 | ahc_echo (void *cls, | ||
271 | struct MHD_Connection *connection, | ||
272 | const char *url, | ||
273 | const char *method, | ||
274 | const char *version, | ||
275 | const char *upload_data, | ||
276 | size_t *upload_data_size, | ||
277 | void **req_cls) | ||
278 | { | ||
279 | struct MHD_Response *response; | ||
280 | char *username; | ||
281 | char *password; | ||
282 | enum MHD_Result ret; | ||
283 | static int already_called_marker; | ||
284 | (void) cls; (void) url; /* Unused. Silent compiler warning. */ | ||
285 | (void) method; (void) version; (void) upload_data; /* Unused. Silent compiler warning. */ | ||
286 | (void) upload_data_size; /* Unused. Silent compiler warning. */ | ||
287 | |||
288 | if (&already_called_marker != *req_cls) | ||
289 | { /* Called for the first time, request not fully read yet */ | ||
290 | *req_cls = &already_called_marker; | ||
291 | /* Wait for complete request */ | ||
292 | return MHD_YES; | ||
293 | } | ||
294 | |||
295 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) | ||
296 | mhdErrorExitDesc ("Unexpected HTTP method"); | ||
297 | |||
298 | /* require: USERNAME with password PASSWORD */ | ||
299 | password = NULL; | ||
300 | username = MHD_basic_auth_get_username_password (connection, | ||
301 | &password); | ||
302 | if (NULL != username) | ||
303 | { | ||
304 | if (0 != strcmp (username, USERNAME)) | ||
305 | { | ||
306 | fprintf (stderr, "'username' does not match.\n" | ||
307 | "Expected: '%s'\tRecieved: '%s'. ", USERNAME, username); | ||
308 | mhdErrorExitDesc ("Wrong 'username'"); | ||
309 | } | ||
310 | if (NULL == password) | ||
311 | mhdErrorExitDesc ("The password pointer is NULL"); | ||
312 | if (0 != strcmp (password, PASSWORD)) | ||
313 | fprintf (stderr, "'password' does not match.\n" | ||
314 | "Expected: '%s'\tRecieved: '%s'. ", PASSWORD, password); | ||
315 | response = | ||
316 | MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), | ||
317 | (const void *) PAGE); | ||
318 | if (NULL == response) | ||
319 | mhdErrorExitDesc ("Response creation failed"); | ||
320 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
321 | if (MHD_YES != ret) | ||
322 | mhdErrorExitDesc ("'MHD_queue_response()' failed"); | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | if (NULL != password) | ||
327 | mhdErrorExitDesc ("The password pointer is NOT NULL"); | ||
328 | response = | ||
329 | MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (DENIED), | ||
330 | (const void *) DENIED); | ||
331 | ret = MHD_queue_basic_auth_fail_response (connection, REALM, | ||
332 | response); | ||
333 | } | ||
334 | |||
335 | if (NULL != username) | ||
336 | MHD_free (username); | ||
337 | if (NULL != password) | ||
338 | MHD_free (password); | ||
339 | MHD_destroy_response (response); | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | |||
344 | static CURL * | ||
345 | setupCURL (void *cbc, int port, char *errbuf) | ||
346 | { | ||
347 | CURL *c; | ||
348 | char url[512]; | ||
349 | |||
350 | if (1) | ||
351 | { | ||
352 | int res; | ||
353 | /* A workaround for some old libcurl versions, which ignore the specified | ||
354 | * port by CURLOPT_PORT when authorisation is used. */ | ||
355 | res = snprintf (url, (sizeof(url) / sizeof(url[0])), | ||
356 | "http://127.0.0.1:%d%s", port, MHD_URI_BASE_PATH); | ||
357 | if ((0 >= res) || ((sizeof(url) / sizeof(url[0])) <= (size_t) res)) | ||
358 | externalErrorExitDesc ("Cannot form request URL"); | ||
359 | } | ||
360 | |||
361 | c = curl_easy_init (); | ||
362 | if (NULL == c) | ||
363 | libcurlErrorExitDesc ("curl_easy_init() failed"); | ||
364 | |||
365 | if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || | ||
366 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, | ||
367 | errbuf)) || | ||
368 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, | ||
369 | ©Buffer)) || | ||
370 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) || | ||
371 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, | ||
372 | ((long) TIMEOUTS_VAL))) || | ||
373 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, | ||
374 | ((long) TIMEOUTS_VAL))) || | ||
375 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, | ||
376 | CURL_HTTP_VERSION_1_1)) || | ||
377 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || | ||
378 | #if CURL_AT_LEAST_VERSION (7, 19, 4) | ||
379 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) || | ||
380 | #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */ | ||
381 | #if CURL_AT_LEAST_VERSION (7, 45, 0) | ||
382 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) || | ||
383 | #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */ | ||
384 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))) || | ||
385 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, url))) | ||
386 | libcurlErrorExitDesc ("curl_easy_setopt() failed"); | ||
387 | if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_BASIC)) || | ||
388 | (CURLE_OK != curl_easy_setopt (c, CURLOPT_USERPWD, | ||
389 | USERNAME ":" PASSWORD))) | ||
390 | libcurlErrorExitDesc ("curl_easy_setopt() authorization options failed"); | ||
391 | return c; | ||
392 | } | ||
393 | |||
394 | |||
395 | static CURLcode | ||
396 | performQueryExternal (struct MHD_Daemon *d, CURL *c) | ||
397 | { | ||
398 | CURLM *multi; | ||
399 | time_t start; | ||
400 | struct timeval tv; | ||
401 | CURLcode ret; | ||
402 | |||
403 | ret = CURLE_FAILED_INIT; /* will be replaced with real result */ | ||
404 | multi = NULL; | ||
405 | multi = curl_multi_init (); | ||
406 | if (multi == NULL) | ||
407 | libcurlErrorExitDesc ("curl_multi_init() failed"); | ||
408 | if (CURLM_OK != curl_multi_add_handle (multi, c)) | ||
409 | libcurlErrorExitDesc ("curl_multi_add_handle() failed"); | ||
410 | |||
411 | start = time (NULL); | ||
412 | while (time (NULL) - start <= TIMEOUTS_VAL) | ||
413 | { | ||
414 | fd_set rs; | ||
415 | fd_set ws; | ||
416 | fd_set es; | ||
417 | MHD_socket maxMhdSk; | ||
418 | int maxCurlSk; | ||
419 | int running; | ||
420 | |||
421 | maxMhdSk = MHD_INVALID_SOCKET; | ||
422 | maxCurlSk = -1; | ||
423 | FD_ZERO (&rs); | ||
424 | FD_ZERO (&ws); | ||
425 | FD_ZERO (&es); | ||
426 | if (NULL != multi) | ||
427 | { | ||
428 | curl_multi_perform (multi, &running); | ||
429 | if (0 == running) | ||
430 | { | ||
431 | struct CURLMsg *msg; | ||
432 | int msgLeft; | ||
433 | int totalMsgs = 0; | ||
434 | do | ||
435 | { | ||
436 | msg = curl_multi_info_read (multi, &msgLeft); | ||
437 | if (NULL == msg) | ||
438 | libcurlErrorExitDesc ("curl_multi_info_read() failed"); | ||
439 | totalMsgs++; | ||
440 | if (CURLMSG_DONE == msg->msg) | ||
441 | ret = msg->data.result; | ||
442 | } while (msgLeft > 0); | ||
443 | if (1 != totalMsgs) | ||
444 | { | ||
445 | fprintf (stderr, | ||
446 | "curl_multi_info_read returned wrong " | ||
447 | "number of results (%d).\n", | ||
448 | totalMsgs); | ||
449 | externalErrorExit (); | ||
450 | } | ||
451 | curl_multi_remove_handle (multi, c); | ||
452 | curl_multi_cleanup (multi); | ||
453 | multi = NULL; | ||
454 | } | ||
455 | else | ||
456 | { | ||
457 | if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) | ||
458 | libcurlErrorExitDesc ("curl_multi_fdset() failed"); | ||
459 | } | ||
460 | } | ||
461 | if (NULL == multi) | ||
462 | { /* libcurl has finished, check whether MHD still needs to perform cleanup */ | ||
463 | if (0 != MHD_get_timeout64s (d)) | ||
464 | break; /* MHD finished as well */ | ||
465 | } | ||
466 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) | ||
467 | mhdErrorExitDesc ("MHD_get_fdset() failed"); | ||
468 | tv.tv_sec = 0; | ||
469 | tv.tv_usec = 200000; | ||
470 | #ifdef MHD_POSIX_SOCKETS | ||
471 | if (maxMhdSk > maxCurlSk) | ||
472 | maxCurlSk = maxMhdSk; | ||
473 | #endif /* MHD_POSIX_SOCKETS */ | ||
474 | if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) | ||
475 | { | ||
476 | #ifdef MHD_POSIX_SOCKETS | ||
477 | if (EINTR != errno) | ||
478 | externalErrorExitDesc ("Unexpected select() error"); | ||
479 | #else | ||
480 | if ((WSAEINVAL != WSAGetLastError ()) || | ||
481 | (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) | ||
482 | externalErrorExitDesc ("Unexpected select() error"); | ||
483 | Sleep (200); | ||
484 | #endif | ||
485 | } | ||
486 | if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) | ||
487 | mhdErrorExitDesc ("MHD_run_from_select() failed"); | ||
488 | } | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Check request result | ||
496 | * @param curl_code the CURL easy return code | ||
497 | * @param pcbc the pointer struct CBC | ||
498 | * @return non-zero if success, zero if failed | ||
499 | */ | ||
500 | static unsigned int | ||
501 | check_result (CURLcode curl_code, struct CBC *pcbc) | ||
502 | { | ||
503 | if (CURLE_OK != curl_code) | ||
504 | { | ||
505 | fflush (stdout); | ||
506 | if (0 != libcurl_errbuf[0]) | ||
507 | fprintf (stderr, "First request failed. " | ||
508 | "libcurl error: '%s'.\n" | ||
509 | "libcurl error description: '%s'.\n", | ||
510 | curl_easy_strerror (curl_code), | ||
511 | libcurl_errbuf); | ||
512 | else | ||
513 | fprintf (stderr, "First request failed. " | ||
514 | "libcurl error: '%s'.\n", | ||
515 | curl_easy_strerror (curl_code)); | ||
516 | fflush (stderr); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | if (pcbc->pos != strlen (PAGE)) | ||
521 | { | ||
522 | fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", | ||
523 | (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf, | ||
524 | (unsigned) strlen (PAGE)); | ||
525 | mhdErrorExitDesc ("Wrong returned data length"); | ||
526 | } | ||
527 | if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos)) | ||
528 | { | ||
529 | fprintf (stderr, "Got invalid response '%.*s'. ", | ||
530 | (int) pcbc->pos, pcbc->buf); | ||
531 | mhdErrorExitDesc ("Wrong returned data"); | ||
532 | } | ||
533 | return 1; | ||
534 | } | ||
535 | |||
536 | |||
537 | static unsigned int | ||
538 | testBasicAuth (void) | ||
539 | { | ||
540 | struct MHD_Daemon *d; | ||
541 | uint16_t port; | ||
542 | struct CBC cbc; | ||
543 | char buf[2048]; | ||
544 | CURL *c; | ||
545 | int failed = 0; | ||
546 | |||
547 | if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) | ||
548 | port = 0; | ||
549 | else | ||
550 | port = 4210; | ||
551 | |||
552 | d = MHD_start_daemon (MHD_USE_ERROR_LOG, | ||
553 | port, NULL, NULL, | ||
554 | &ahc_echo, NULL, | ||
555 | MHD_OPTION_END); | ||
556 | if (d == NULL) | ||
557 | return 1; | ||
558 | if (0 == port) | ||
559 | { | ||
560 | const union MHD_DaemonInfo *dinfo; | ||
561 | |||
562 | dinfo = MHD_get_daemon_info (d, | ||
563 | MHD_DAEMON_INFO_BIND_PORT); | ||
564 | if ( (NULL == dinfo) || | ||
565 | (0 == dinfo->port) ) | ||
566 | mhdErrorExitDesc ("MHD_get_daemon_info() failed"); | ||
567 | port = (uint16_t) dinfo->port; | ||
568 | } | ||
569 | |||
570 | /* First request */ | ||
571 | cbc.buf = buf; | ||
572 | cbc.size = sizeof (buf); | ||
573 | cbc.pos = 0; | ||
574 | memset (cbc.buf, 0, cbc.size); | ||
575 | c = setupCURL (&cbc, port, libcurl_errbuf); | ||
576 | if (check_result (performQueryExternal (d, c), &cbc)) | ||
577 | { | ||
578 | if (verbose) | ||
579 | printf ("First request successful.\n"); | ||
580 | } | ||
581 | else | ||
582 | { | ||
583 | fprintf (stderr, "First request FAILED.\n"); | ||
584 | failed = 1; | ||
585 | } | ||
586 | curl_easy_cleanup (c); | ||
587 | |||
588 | /* Second request */ | ||
589 | cbc.buf = buf; | ||
590 | cbc.size = sizeof (buf); | ||
591 | cbc.pos = 0; | ||
592 | memset (cbc.buf, 0, cbc.size); | ||
593 | c = setupCURL (&cbc, port, libcurl_errbuf); | ||
594 | if (check_result (performQueryExternal (d, c), &cbc)) | ||
595 | { | ||
596 | if (verbose) | ||
597 | printf ("Second request successful.\n"); | ||
598 | } | ||
599 | else | ||
600 | { | ||
601 | fprintf (stderr, "Second request FAILED.\n"); | ||
602 | failed = 1; | ||
603 | } | ||
604 | curl_easy_cleanup (c); | ||
605 | MHD_stop_daemon (d); | ||
606 | return failed ? 1 : 0; | ||
607 | } | ||
608 | |||
609 | |||
610 | int | ||
611 | main (int argc, char *const *argv) | ||
612 | { | ||
613 | unsigned int errorCount = 0; | ||
614 | (void) argc; (void) argv; /* Unused. Silent compiler warning. */ | ||
615 | |||
616 | verbose = ! (has_param (argc, argv, "-q") || | ||
617 | has_param (argc, argv, "--quiet") || | ||
618 | has_param (argc, argv, "-s") || | ||
619 | has_param (argc, argv, "--silent")); | ||
620 | |||
621 | #ifdef MHD_HTTPS_REQUIRE_GRYPT | ||
622 | #ifdef HAVE_GCRYPT_H | ||
623 | gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); | ||
624 | #ifdef GCRYCTL_INITIALIZATION_FINISHED | ||
625 | gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); | ||
626 | #endif | ||
627 | #endif | ||
628 | #endif /* MHD_HTTPS_REQUIRE_GRYPT */ | ||
629 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
630 | return 2; | ||
631 | errorCount += testBasicAuth (); | ||
632 | if (errorCount != 0) | ||
633 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
634 | curl_global_cleanup (); | ||
635 | return (0 == errorCount) ? 0 : 1; /* 0 == pass */ | ||
636 | } | ||