aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/test_head.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/test_head.c')
-rw-r--r--src/testcurl/test_head.c809
1 files changed, 809 insertions, 0 deletions
diff --git a/src/testcurl/test_head.c b/src/testcurl/test_head.c
new file mode 100644
index 00000000..f435a4f4
--- /dev/null
+++ b/src/testcurl/test_head.c
@@ -0,0 +1,809 @@
1/*
2 This file is part of GNU libmicrohttpd
3 Copyright (C) 2010 Christian Grothoff
4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
5
6 GNU 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 GNU 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 testcurl/test_head.c
24 * @brief Testcase for HEAD requests
25 * @author Karlson2k (Evgeny Grin)
26 */
27
28#include "mhd_options.h"
29#include "platform.h"
30#include <curl/curl.h>
31#include <microhttpd.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35
36#ifndef _WIN32
37#include <sys/socket.h>
38#include <unistd.h>
39#else
40#include <wincrypt.h>
41#endif
42
43#include "mhd_has_param.h"
44#include "mhd_has_in_name.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, \
113 __LINE__)
114#endif
115
116
117_MHD_NORETURN static void
118_externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
119{
120 fflush (stdout);
121 if ((NULL != errDesc) && (0 != errDesc[0]))
122 fprintf (stderr, "%s", errDesc);
123 else
124 fprintf (stderr, "System or external library call failed");
125 if ((NULL != funcName) && (0 != funcName[0]))
126 fprintf (stderr, " in %s", funcName);
127 if (0 < lineNum)
128 fprintf (stderr, " at line %d", lineNum);
129
130 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
131 strerror (errno));
132#ifdef MHD_WINSOCK_SOCKETS
133 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
134#endif /* MHD_WINSOCK_SOCKETS */
135 fflush (stderr);
136 exit (99);
137}
138
139
140static 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/* Could be increased to facilitate debugging */
193#define TIMEOUTS_VAL 5
194
195#define EXPECTED_URI_BASE_PATH "/"
196
197#define EXISTING_URI EXPECTED_URI_BASE_PATH
198
199#define EXPECTED_URI_BASE_PATH_MISSING "/wrong_uri"
200
201#define URL_SCHEME "http:/" "/"
202
203#define URL_HOST "127.0.0.1"
204
205#define URL_SCHEME_HOST URL_SCHEME URL_HOST
206
207#define HEADER1_NAME "First"
208#define HEADER1_VALUE "1st"
209#define HEADER1 HEADER1_NAME ": " HEADER1_VALUE
210#define HEADER1_CRLF HEADER1 "\r\n"
211#define HEADER2_NAME "Normal"
212#define HEADER2_VALUE "it's fine"
213#define HEADER2 HEADER2_NAME ": " HEADER2_VALUE
214#define HEADER2_CRLF HEADER2 "\r\n"
215
216#define PAGE \
217 "<html><head><title>libmicrohttpd demo page</title></head>" \
218 "<body>Success!</body></html>"
219
220#define PAGE_404 \
221 "<html><head><title>404 error</title></head>" \
222 "<body>Error 404: The requested URI does not exist</body></html>"
223
224/* Global parameters */
225static int verbose;
226static int oneone; /**< If false use HTTP/1.0 for requests*/
227
228static void
229test_global_init (void)
230{
231 libcurl_errbuf[0] = 0;
232
233 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
234 externalErrorExit ();
235}
236
237
238static void
239test_global_cleanup (void)
240{
241 curl_global_cleanup ();
242}
243
244
245struct headers_check_result
246{
247 unsigned int expected_size;
248 int header1_found;
249 int header2_found;
250 int size_found;
251};
252
253static size_t
254lcurl_hdr_callback (char *buffer, size_t size, size_t nitems,
255 void *userdata)
256{
257 const size_t data_size = size * nitems;
258 struct headers_check_result *check_res =
259 (struct headers_check_result *) userdata;
260
261 if ((MHD_STATICSTR_LEN_ (HEADER1_CRLF) == data_size) &&
262 (0 == memcmp (HEADER1_CRLF, buffer, data_size)))
263 check_res->header1_found++;
264 else if ((MHD_STATICSTR_LEN_ (HEADER2_CRLF) == data_size) &&
265 (0 == memcmp (HEADER2_CRLF, buffer, data_size)))
266 check_res->header2_found++;
267 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ")
268 < data_size) &&
269 (0 ==
270 memcmp (MHD_HTTP_HEADER_CONTENT_LENGTH ": ", buffer,
271 MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": "))))
272 {
273 char cmpbuf[256];
274 int res;
275 const unsigned int numbers_pos =
276 MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ");
277 res = snprintf (cmpbuf, sizeof(cmpbuf), "%u\r\n", check_res->expected_size);
278 if ((res <= 0) || (res > ((int) (sizeof(cmpbuf) - 1))))
279 externalErrorExit ();
280 if (0 != strcmp (buffer + numbers_pos, cmpbuf))
281 {
282 fprintf (stderr, "Wrong Content-Length.\n"
283 "Expected:\n%u\n"
284 "Received:\n%s", check_res->expected_size,
285 buffer + numbers_pos);
286 mhdErrorExitDesc ("Wrong Content-Length");
287 }
288 check_res->size_found++;
289 }
290
291 return data_size;
292}
293
294
295struct CBC
296{
297 char *buf;
298 size_t pos;
299 size_t size;
300};
301
302
303static size_t
304copyBuffer (void *ptr,
305 size_t size,
306 size_t nmemb,
307 void *ctx)
308{
309 (void) ptr; /* Unused, mute compiler warning */
310 (void) ctx; /* Unused, mute compiler warning */
311 if ((0 != size) && (0 != nmemb))
312 libcurlErrorExitDesc ("Received unexpected body data");
313 return size * nmemb;
314}
315
316
317struct ahc_cls_type
318{
319 const char *rq_method;
320 const char *rq_url;
321};
322
323
324static enum MHD_Result
325ahcCheck (void *cls,
326 struct MHD_Connection *connection,
327 const char *url,
328 const char *method,
329 const char *version,
330 const char *upload_data, size_t *upload_data_size,
331 void **req_cls)
332{
333 static int marker;
334 struct MHD_Response *response;
335 enum MHD_Result ret;
336 struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
337 unsigned int http_code;
338
339 if (NULL == param)
340 mhdErrorExitDesc ("cls parameter is NULL");
341
342 if (oneone)
343 {
344 if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
345 mhdErrorExitDesc ("Unexpected HTTP version");
346 }
347 else
348 {
349 if (0 != strcmp (version, MHD_HTTP_VERSION_1_0))
350 mhdErrorExitDesc ("Unexpected HTTP version");
351 }
352
353 if (0 != strcmp (url, param->rq_url))
354 mhdErrorExitDesc ("Unexpected URI");
355
356 if (NULL != upload_data)
357 mhdErrorExitDesc ("'upload_data' is not NULL");
358
359 if (NULL == upload_data_size)
360 mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
361
362 if (0 != *upload_data_size)
363 mhdErrorExitDesc ("'*upload_data_size' value is not zero");
364
365 if (0 != strcmp (param->rq_method, method))
366 mhdErrorExitDesc ("Unexpected request method");
367
368 if (&marker != *req_cls)
369 {
370 *req_cls = &marker;
371 return MHD_YES;
372 }
373 *req_cls = NULL;
374
375 if (0 == strcmp (url, EXISTING_URI))
376 {
377 response =
378 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
379 PAGE);
380 http_code = MHD_HTTP_OK;
381 }
382 else
383 {
384 response =
385 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE_404),
386 PAGE_404);
387 http_code = MHD_HTTP_NOT_FOUND;
388 }
389 if (NULL == response)
390 mhdErrorExitDesc ("Failed to create response");
391
392 if (MHD_YES != MHD_add_response_header (response,
393 HEADER1_NAME,
394 HEADER1_VALUE))
395 mhdErrorExitDesc ("Cannot add header1");
396 if (MHD_YES != MHD_add_response_header (response,
397 HEADER2_NAME,
398 HEADER2_VALUE))
399 mhdErrorExitDesc ("Cannot add header2");
400
401 ret = MHD_queue_response (connection,
402 http_code,
403 response);
404 MHD_destroy_response (response);
405 if (MHD_YES != ret)
406 mhdErrorExitDesc ("Failed to queue response");
407
408 return ret;
409}
410
411
412/**
413 * Set required URI for the request
414 * @param c the CURL handle to use
415 * @param uri_exist if non-zero use request for "existing" URI
416 */
417static void
418setCURL_rq_path (CURL *c, int uri_exist)
419{
420 if (uri_exist)
421 {
422 if (CURLE_OK !=
423 curl_easy_setopt (c, CURLOPT_URL,
424 URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
425 libcurlErrorExitDesc ("Cannot set request URL");
426 }
427 else
428 {
429 if (CURLE_OK !=
430 curl_easy_setopt (c, CURLOPT_URL,
431 URL_SCHEME_HOST EXPECTED_URI_BASE_PATH_MISSING))
432 libcurlErrorExitDesc ("Cannot set request URL");
433 }
434}
435
436
437static CURL *
438setupCURL (void *cbc, unsigned int port,
439 struct headers_check_result *hdr_chk_result)
440{
441 CURL *c;
442
443 c = curl_easy_init ();
444 if (NULL == c)
445 libcurlErrorExitDesc ("curl_easy_init() failed");
446
447 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
448 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
449 &copyBuffer)) ||
450 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) ||
451 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
452 ((long) TIMEOUTS_VAL))) ||
453 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
454 (oneone) ?
455 CURL_HTTP_VERSION_1_1 :
456 CURL_HTTP_VERSION_1_0)) ||
457 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
458 ((long) TIMEOUTS_VAL))) ||
459 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERFUNCTION,
460 lcurl_hdr_callback)) ||
461 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERDATA,
462 hdr_chk_result)) ||
463 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
464 libcurl_errbuf)) ||
465 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
466#ifdef _DEBUG
467 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
468#endif /* _DEBUG */
469#if CURL_AT_LEAST_VERSION (7, 19, 4)
470 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
471#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
472#if CURL_AT_LEAST_VERSION (7, 45, 0)
473 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) ||
474#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
475 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))))
476 libcurlErrorExitDesc ("curl_easy_setopt() failed");
477
478 /* When 'CURLOPT_NOBODY' is set, libcurl should use HEAD request. */
479 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_NOBODY, (long) 1))
480 libcurlErrorExitDesc ("curl_easy_setopt() failed");
481
482 return c;
483}
484
485
486static CURLcode
487performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse)
488{
489 CURLM *multi;
490 time_t start;
491 struct timeval tv;
492 CURLcode ret;
493
494 ret = CURLE_FAILED_INIT; /* will be replaced with real result */
495 if (NULL != *multi_reuse)
496 multi = *multi_reuse;
497 else
498 {
499 multi = curl_multi_init ();
500 if (multi == NULL)
501 libcurlErrorExitDesc ("curl_multi_init() failed");
502 *multi_reuse = multi;
503 }
504 if (CURLM_OK != curl_multi_add_handle (multi, c))
505 libcurlErrorExitDesc ("curl_multi_add_handle() failed");
506
507 start = time (NULL);
508 while (time (NULL) - start <= TIMEOUTS_VAL)
509 {
510 fd_set rs;
511 fd_set ws;
512 fd_set es;
513 MHD_socket maxMhdSk;
514 int maxCurlSk;
515 int running;
516
517 maxMhdSk = MHD_INVALID_SOCKET;
518 maxCurlSk = -1;
519 FD_ZERO (&rs);
520 FD_ZERO (&ws);
521 FD_ZERO (&es);
522 if (NULL != multi)
523 {
524 curl_multi_perform (multi, &running);
525 if (0 == running)
526 {
527 struct CURLMsg *msg;
528 int msgLeft;
529 int totalMsgs = 0;
530 do
531 {
532 msg = curl_multi_info_read (multi, &msgLeft);
533 if (NULL == msg)
534 libcurlErrorExitDesc ("curl_multi_info_read() failed");
535 totalMsgs++;
536 if (CURLMSG_DONE == msg->msg)
537 ret = msg->data.result;
538 } while (msgLeft > 0);
539 if (1 != totalMsgs)
540 {
541 fprintf (stderr,
542 "curl_multi_info_read returned wrong "
543 "number of results (%d).\n",
544 totalMsgs);
545 externalErrorExit ();
546 }
547 curl_multi_remove_handle (multi, c);
548 multi = NULL;
549 }
550 else
551 {
552 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk))
553 libcurlErrorExitDesc ("curl_multi_fdset() failed");
554 }
555 }
556 if (NULL == multi)
557 { /* libcurl has finished, check whether MHD still needs to perform cleanup */
558 if (0 != MHD_get_timeout64s (d))
559 break; /* MHD finished as well */
560 }
561 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
562 mhdErrorExitDesc ("MHD_get_fdset() failed");
563 tv.tv_sec = 0;
564 tv.tv_usec = 200000;
565#ifdef MHD_POSIX_SOCKETS
566 if (maxMhdSk > maxCurlSk)
567 maxCurlSk = maxMhdSk;
568#endif /* MHD_POSIX_SOCKETS */
569 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv))
570 {
571#ifdef MHD_POSIX_SOCKETS
572 if (EINTR != errno)
573 externalErrorExitDesc ("Unexpected select() error");
574#else
575 if ((WSAEINVAL != WSAGetLastError ()) ||
576 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
577 externalErrorExitDesc ("Unexpected select() error");
578 Sleep (200);
579#endif
580 }
581 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
582 mhdErrorExitDesc ("MHD_run_from_select() failed");
583 }
584
585 return ret;
586}
587
588
589/**
590 * Check request result
591 * @param curl_code the CURL easy return code
592 * @param pcbc the pointer struct CBC
593 * @return non-zero if success, zero if failed
594 */
595static unsigned int
596check_result (CURLcode curl_code, CURL *c, long expected_code,
597 struct headers_check_result *hdr_res)
598{
599 long code;
600 unsigned int ret;
601
602 if (CURLE_OK != curl_code)
603 {
604 fflush (stdout);
605 if (0 != libcurl_errbuf[0])
606 fprintf (stderr, "Request failed. "
607 "libcurl error: '%s'.\n"
608 "libcurl error description: '%s'.\n",
609 curl_easy_strerror (curl_code),
610 libcurl_errbuf);
611 else
612 fprintf (stderr, "Request failed. "
613 "libcurl error: '%s'.\n",
614 curl_easy_strerror (curl_code));
615 fflush (stderr);
616 return 0;
617 }
618
619 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
620 libcurlErrorExit ();
621
622 if (expected_code != code)
623 {
624 fprintf (stderr, "The response has wrong HTTP code: %ld\tExpected: %ld.\n",
625 code, expected_code);
626 return 0;
627 }
628 else if (verbose)
629 printf ("The response has expected HTTP code: %ld\n", expected_code);
630
631 ret = 1;
632 if (1 != hdr_res->header1_found)
633 {
634 if (0 == hdr_res->header1_found)
635 fprintf (stderr, "Response header1 was not found.\n");
636 else
637 fprintf (stderr, "Response header1 was found %d times "
638 "instead of one time only.\n", hdr_res->header1_found);
639 ret = 0;
640 }
641 else if (verbose)
642 printf ("Header1 is present in the response.\n");
643 if (1 != hdr_res->header2_found)
644 {
645 if (0 == hdr_res->header2_found)
646 fprintf (stderr, "Response header2 was not found.\n");
647 else
648 fprintf (stderr, "Response header2 was found %d times "
649 "instead of one time only.\n", hdr_res->header2_found);
650 ret = 0;
651 }
652 else if (verbose)
653 printf ("Header2 is present in the response.\n");
654 if (1 != hdr_res->size_found)
655 {
656 if (0 == hdr_res->size_found)
657 fprintf (stderr, "Response 'Content-Length' header was not found.\n");
658 else
659 fprintf (stderr, "Response 'Content-Length' header was found %d times "
660 "instead of one time only.\n", hdr_res->size_found);
661 ret = 0;
662 }
663 else if (verbose)
664 printf ("'Content-Length' header with correct value "
665 "is present in the response.\n");
666
667 return ret;
668}
669
670
671static unsigned int
672testHead (void)
673{
674 struct MHD_Daemon *d;
675 uint16_t port;
676 struct CBC cbc;
677 struct ahc_cls_type ahc_param;
678 struct headers_check_result rp_headers_check;
679 char buf[2048];
680 CURL *c;
681 CURLM *multi_reuse;
682 int failed = 0;
683
684 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
685 port = 0;
686 else
687 port = 4220 + oneone ? 0 : 1;
688
689 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
690 port, NULL, NULL,
691 &ahcCheck, &ahc_param,
692 MHD_OPTION_END);
693 if (d == NULL)
694 return 1;
695 if (0 == port)
696 {
697 const union MHD_DaemonInfo *dinfo;
698
699 dinfo = MHD_get_daemon_info (d,
700 MHD_DAEMON_INFO_BIND_PORT);
701 if ( (NULL == dinfo) ||
702 (0 == dinfo->port) )
703 mhdErrorExitDesc ("MHD_get_daemon_info() failed");
704 port = dinfo->port;
705 }
706
707 /* First request */
708 ahc_param.rq_method = MHD_HTTP_METHOD_HEAD;
709 ahc_param.rq_url = EXPECTED_URI_BASE_PATH;
710 rp_headers_check.expected_size = MHD_STATICSTR_LEN_ (PAGE);
711 rp_headers_check.header1_found = 0;
712 rp_headers_check.header2_found = 0;
713 rp_headers_check.size_found = 0;
714 cbc.buf = buf;
715 cbc.size = sizeof (buf);
716 cbc.pos = 0;
717 memset (cbc.buf, 0, cbc.size);
718 c = setupCURL (&cbc, (unsigned int) port, &rp_headers_check);
719 setCURL_rq_path (c, 1);
720 multi_reuse = NULL;
721 /* First request */
722 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
723 MHD_HTTP_OK, &rp_headers_check))
724 {
725 fflush (stderr);
726 if (verbose)
727 printf ("Got first expected response.\n");
728 fflush (stdout);
729 }
730 else
731 {
732 fprintf (stderr, "First request FAILED.\n");
733 fflush (stderr);
734 failed = 1;
735 }
736 /* Second request */
737 rp_headers_check.expected_size = MHD_STATICSTR_LEN_ (PAGE_404);
738 rp_headers_check.header1_found = 0;
739 rp_headers_check.header2_found = 0;
740 rp_headers_check.size_found = 0;
741 cbc.pos = 0; /* Reset buffer position */
742 ahc_param.rq_url = EXPECTED_URI_BASE_PATH_MISSING;
743 setCURL_rq_path (c, 0);
744 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
745 MHD_HTTP_NOT_FOUND, &rp_headers_check))
746 {
747 fflush (stderr);
748 if (verbose)
749 printf ("Got second expected response.\n");
750 fflush (stdout);
751 }
752 else
753 {
754 fprintf (stderr, "Second request FAILED.\n");
755 fflush (stderr);
756 failed = 1;
757 }
758 /* Third request */
759 rp_headers_check.header1_found = 0;
760 rp_headers_check.header2_found = 0;
761 rp_headers_check.size_found = 0;
762 cbc.pos = 0; /* Reset buffer position */
763 if (NULL != multi_reuse)
764 curl_multi_cleanup (multi_reuse);
765 multi_reuse = NULL; /* Force new connection */
766 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
767 MHD_HTTP_NOT_FOUND, &rp_headers_check))
768 {
769 fflush (stderr);
770 if (verbose)
771 printf ("Got third expected response.\n");
772 fflush (stdout);
773 }
774 else
775 {
776 fprintf (stderr, "Third request FAILED.\n");
777 fflush (stderr);
778 failed = 1;
779 }
780
781 curl_easy_cleanup (c);
782 if (NULL != multi_reuse)
783 curl_multi_cleanup (multi_reuse);
784
785 MHD_stop_daemon (d);
786 return failed ? 1 : 0;
787}
788
789
790int
791main (int argc, char *const *argv)
792{
793 unsigned int errorCount = 0;
794
795 /* Test type and test parameters */
796 verbose = ! (has_param (argc, argv, "-q") ||
797 has_param (argc, argv, "--quiet") ||
798 has_param (argc, argv, "-s") ||
799 has_param (argc, argv, "--silent"));
800 oneone = ! has_in_name (argv[0], "10");
801
802 test_global_init ();
803
804 errorCount += testHead ();
805 if (errorCount != 0)
806 fprintf (stderr, "Error (code: %u)\n", errorCount);
807 test_global_cleanup ();
808 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
809}