aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-10-23 12:04:06 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-10-28 12:10:18 +0300
commit9b86ff304c83ffee301130925a233635a0be72a5 (patch)
treeaa1eae71f87d4dd6a489ecf913f0785ad4ad484a
parentf1bfbe71dcb3c6d30c6d89e165deda6778d422d5 (diff)
downloadlibmicrohttpd-9b86ff304c83ffee301130925a233635a0be72a5.tar.gz
libmicrohttpd-9b86ff304c83ffee301130925a233635a0be72a5.zip
testcurl: added test with Content-Length broken value in request
-rw-r--r--src/testcurl/Makefile.am7
-rw-r--r--src/testcurl/test_put_broken_len.c734
2 files changed, 741 insertions, 0 deletions
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index 13f9fed7..11a489c3 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -114,6 +114,8 @@ check_PROGRAMS = \
114 test_put11 \ 114 test_put11 \
115 test_large_put11 \ 115 test_large_put11 \
116 test_large_put_inc11 \ 116 test_large_put_inc11 \
117 test_put_broken_len10 \
118 test_put_broken_len \
117 test_get_chunked \ 119 test_get_chunked \
118 test_get_chunked_close \ 120 test_get_chunked_close \
119 test_get_chunked_string \ 121 test_get_chunked_string \
@@ -607,3 +609,8 @@ test_tricky_url_SOURCES = \
607 609
608test_tricky_header2_SOURCES = \ 610test_tricky_header2_SOURCES = \
609 test_tricky.c mhd_has_in_name.h mhd_has_param.h 611 test_tricky.c mhd_has_in_name.h mhd_has_param.h
612
613test_put_broken_len_SOURCES = \
614 test_put_broken_len.c mhd_has_in_name.h mhd_has_param.h
615
616test_put_broken_len10_SOURCES = $(test_put_broken_len_SOURCES)
diff --git a/src/testcurl/test_put_broken_len.c b/src/testcurl/test_put_broken_len.c
new file mode 100644
index 00000000..18e22e2d
--- /dev/null
+++ b/src/testcurl/test_put_broken_len.c
@@ -0,0 +1,734 @@
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 PUT requests with broken Content-Length header
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 500000
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 PAGE \
208 "<html><head><title>libmicrohttpd demo page</title></head>" \
209 "<body>Success!</body></html>"
210
211#define PAGE_404 \
212 "<html><head><title>404 error</title></head>" \
213 "<body>Error 404: The requested URI does not exist</body></html>"
214
215/* Global parameters */
216static int verbose;
217static int oneone; /**< If false use HTTP/1.0 for requests*/
218
219static struct curl_slist *hdr_broken_cnt_len = NULL;
220
221static void
222test_global_init (void)
223{
224 libcurl_errbuf[0] = 0;
225
226 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
227 externalErrorExit ();
228
229 hdr_broken_cnt_len =
230 curl_slist_append (hdr_broken_cnt_len,
231 MHD_HTTP_HEADER_CONTENT_LENGTH ": 123bad");
232}
233
234
235static void
236test_global_cleanup (void)
237{
238 curl_slist_free_all (hdr_broken_cnt_len);
239
240 curl_global_cleanup ();
241}
242
243
244struct CBC
245{
246 char *buf;
247 size_t pos;
248 size_t size;
249};
250
251
252static size_t
253copyBuffer (void *ptr,
254 size_t size,
255 size_t nmemb,
256 void *ctx)
257{
258 (void) ptr; /* Unused, mute compiler warning */
259 (void) ctx; /* Unused, mute compiler warning */
260 /* Discard data */
261 return size * nmemb;
262}
263
264
265struct ahc_cls_type
266{
267 const char *rq_method;
268 const char *rq_url;
269};
270
271
272static enum MHD_Result
273ahcCheck (void *cls,
274 struct MHD_Connection *connection,
275 const char *url,
276 const char *method,
277 const char *version,
278 const char *upload_data, size_t *upload_data_size,
279 void **req_cls)
280{
281 static int marker;
282 struct MHD_Response *response;
283 enum MHD_Result ret;
284 struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
285 unsigned int http_code;
286
287 if (NULL == param)
288 mhdErrorExitDesc ("cls parameter is NULL");
289
290 if (oneone)
291 {
292 if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
293 mhdErrorExitDesc ("Unexpected HTTP version");
294 }
295 else
296 {
297 if (0 != strcmp (version, MHD_HTTP_VERSION_1_0))
298 mhdErrorExitDesc ("Unexpected HTTP version");
299 }
300
301 if (0 != strcmp (url, param->rq_url))
302 mhdErrorExitDesc ("Unexpected URI");
303
304 if (NULL != upload_data)
305 mhdErrorExitDesc ("'upload_data' is not NULL");
306
307 if (NULL == upload_data_size)
308 mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
309
310 if (0 != *upload_data_size)
311 mhdErrorExitDesc ("'*upload_data_size' value is not zero");
312
313 if (0 != strcmp (param->rq_method, method))
314 mhdErrorExitDesc ("Unexpected request method");
315
316 if (&marker != *req_cls)
317 {
318 *req_cls = &marker;
319 return MHD_YES;
320 }
321 *req_cls = NULL;
322
323 if (0 == strcmp (url, EXISTING_URI))
324 {
325 response =
326 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
327 PAGE);
328 http_code = MHD_HTTP_OK;
329 }
330 else
331 {
332 response =
333 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE_404),
334 PAGE_404);
335 http_code = MHD_HTTP_NOT_FOUND;
336 }
337 if (NULL == response)
338 mhdErrorExitDesc ("Failed to create response");
339
340 ret = MHD_queue_response (connection,
341 http_code,
342 response);
343 MHD_destroy_response (response);
344 if (MHD_YES != ret)
345 mhdErrorExitDesc ("Failed to queue response");
346
347 return ret;
348}
349
350
351static int
352libcurl_debug_cb (CURL *handle,
353 curl_infotype type,
354 char *data,
355 size_t size,
356 void *userptr)
357{
358 static const char excess_mark[] = "Excess found";
359 static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
360 (void) handle;
361 (void) userptr;
362
363#ifdef _DEBUG
364 switch (type)
365 {
366 case CURLINFO_TEXT:
367 fprintf (stderr, "* %.*s", (int) size, data);
368 break;
369 case CURLINFO_HEADER_IN:
370 fprintf (stderr, "< %.*s", (int) size, data);
371 break;
372 case CURLINFO_HEADER_OUT:
373 fprintf (stderr, "> %.*s", (int) size, data);
374 break;
375 case CURLINFO_DATA_IN:
376#if 0
377 fprintf (stderr, "<| %.*s\n", (int) size, data);
378#endif
379 break;
380 case CURLINFO_DATA_OUT:
381 case CURLINFO_SSL_DATA_IN:
382 case CURLINFO_SSL_DATA_OUT:
383 case CURLINFO_END:
384 default:
385 break;
386 }
387#endif /* _DEBUG */
388 if (CURLINFO_TEXT == type)
389 {
390 if ((size >= excess_mark_len) &&
391 (0 == memcmp (data, excess_mark, excess_mark_len)))
392 mhdErrorExitDesc ("Extra data has been detected in MHD reply");
393 }
394 return 0;
395}
396
397
398static CURL *
399setupCURL (void *cbc, uint16_t port)
400{
401 CURL *c;
402
403 c = curl_easy_init ();
404 if (NULL == c)
405 libcurlErrorExitDesc ("curl_easy_init() failed");
406
407 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
408 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
409 &copyBuffer)) ||
410 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) ||
411 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
412 ((long) TIMEOUTS_VAL))) ||
413 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
414 (oneone) ?
415 CURL_HTTP_VERSION_1_1 :
416 CURL_HTTP_VERSION_1_0)) ||
417 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
418 ((long) TIMEOUTS_VAL))) ||
419 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
420 libcurl_errbuf)) ||
421 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
422#ifdef _DEBUG
423 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
424#endif /* _DEBUG */
425 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
426 &libcurl_debug_cb)) ||
427#if CURL_AT_LEAST_VERSION (7, 19, 4)
428 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
429#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
430#if CURL_AT_LEAST_VERSION (7, 45, 0)
431 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) ||
432#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
433 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))))
434 libcurlErrorExitDesc ("curl_easy_setopt() failed");
435
436 if (CURLE_OK !=
437 curl_easy_setopt (c, CURLOPT_URL,
438 URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
439 libcurlErrorExitDesc ("Cannot set request URI");
440
441 /* Set as a "custom" request, because no actual upload data is provided. */
442 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST,
443 MHD_HTTP_METHOD_PUT))
444 libcurlErrorExitDesc ("curl_easy_setopt() failed");
445
446 if (CURLE_OK !=
447 curl_easy_setopt (c, CURLOPT_HTTPHEADER,
448 hdr_broken_cnt_len))
449 libcurlErrorExitDesc ("Cannot set '" MHD_HTTP_HEADER_CONTENT_LENGTH "'.\n");
450
451 return c;
452}
453
454
455static CURLcode
456performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse)
457{
458 CURLM *multi;
459 time_t start;
460 struct timeval tv;
461 CURLcode ret;
462
463 ret = CURLE_FAILED_INIT; /* will be replaced with real result */
464 if (NULL != *multi_reuse)
465 multi = *multi_reuse;
466 else
467 {
468 multi = curl_multi_init ();
469 if (multi == NULL)
470 libcurlErrorExitDesc ("curl_multi_init() failed");
471 *multi_reuse = multi;
472 }
473 if (CURLM_OK != curl_multi_add_handle (multi, c))
474 libcurlErrorExitDesc ("curl_multi_add_handle() failed");
475
476 start = time (NULL);
477 while (time (NULL) - start <= TIMEOUTS_VAL)
478 {
479 fd_set rs;
480 fd_set ws;
481 fd_set es;
482 MHD_socket maxMhdSk;
483 int maxCurlSk;
484 int running;
485
486 maxMhdSk = MHD_INVALID_SOCKET;
487 maxCurlSk = -1;
488 FD_ZERO (&rs);
489 FD_ZERO (&ws);
490 FD_ZERO (&es);
491 if (NULL != multi)
492 {
493 curl_multi_perform (multi, &running);
494 if (0 == running)
495 {
496 struct CURLMsg *msg;
497 int msgLeft;
498 int totalMsgs = 0;
499 do
500 {
501 msg = curl_multi_info_read (multi, &msgLeft);
502 if (NULL == msg)
503 libcurlErrorExitDesc ("curl_multi_info_read() failed");
504 totalMsgs++;
505 if (CURLMSG_DONE == msg->msg)
506 ret = msg->data.result;
507 } while (msgLeft > 0);
508 if (1 != totalMsgs)
509 {
510 fprintf (stderr,
511 "curl_multi_info_read returned wrong "
512 "number of results (%d).\n",
513 totalMsgs);
514 externalErrorExit ();
515 }
516 curl_multi_remove_handle (multi, c);
517 multi = NULL;
518 }
519 else
520 {
521 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk))
522 libcurlErrorExitDesc ("curl_multi_fdset() failed");
523 }
524 }
525 if (NULL == multi)
526 { /* libcurl has finished, check whether MHD still needs to perform cleanup */
527 if (0 != MHD_get_timeout64s (d))
528 break; /* MHD finished as well */
529 }
530 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
531 mhdErrorExitDesc ("MHD_get_fdset() failed");
532 tv.tv_sec = 0;
533 tv.tv_usec = 200000;
534 if (0 == MHD_get_timeout64s (d))
535 tv.tv_usec = 0;
536 else
537 {
538 long curl_to = -1;
539 curl_multi_timeout (multi, &curl_to);
540 if (0 == curl_to)
541 tv.tv_usec = 0;
542 }
543#ifdef MHD_POSIX_SOCKETS
544 if (maxMhdSk > maxCurlSk)
545 maxCurlSk = maxMhdSk;
546#endif /* MHD_POSIX_SOCKETS */
547 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv))
548 {
549#ifdef MHD_POSIX_SOCKETS
550 if (EINTR != errno)
551 externalErrorExitDesc ("Unexpected select() error");
552#else
553 if ((WSAEINVAL != WSAGetLastError ()) ||
554 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
555 externalErrorExitDesc ("Unexpected select() error");
556 Sleep ((unsigned long) tv.tv_usec / 1000);
557#endif
558 }
559 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
560 mhdErrorExitDesc ("MHD_run_from_select() failed");
561 }
562
563 return ret;
564}
565
566
567/**
568 * Check request result
569 * @param curl_code the CURL easy return code
570 * @param pcbc the pointer struct CBC
571 * @return non-zero if success, zero if failed
572 */
573static unsigned int
574check_result (CURLcode curl_code, CURL *c, long expected_code)
575{
576 long code;
577
578 if (CURLE_OK != curl_code)
579 {
580 fflush (stdout);
581 if (0 != libcurl_errbuf[0])
582 fprintf (stderr, "Request failed. "
583 "libcurl error: '%s'.\n"
584 "libcurl error description: '%s'.\n",
585 curl_easy_strerror (curl_code),
586 libcurl_errbuf);
587 else
588 fprintf (stderr, "Request failed. "
589 "libcurl error: '%s'.\n",
590 curl_easy_strerror (curl_code));
591 fflush (stderr);
592 return 0;
593 }
594
595 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
596 libcurlErrorExit ();
597
598 if (expected_code != code)
599 {
600 fprintf (stderr, "The response has wrong HTTP code: %ld\tExpected: %ld.\n",
601 code, expected_code);
602 return 0;
603 }
604 else if (verbose)
605 printf ("The response has expected HTTP code: %ld\n", expected_code);
606
607 return ! 0;
608}
609
610
611static unsigned int
612performTest (void)
613{
614 struct MHD_Daemon *d;
615 uint16_t port;
616 struct CBC cbc;
617 struct ahc_cls_type ahc_param;
618 char buf[2048];
619 CURL *c;
620 CURLM *multi_reuse;
621 int failed = 0;
622
623 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
624 port = 0;
625 else
626 port = 4220 + oneone ? 0 : 1;
627
628 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
629 port, NULL, NULL,
630 &ahcCheck, &ahc_param,
631 MHD_OPTION_END);
632 if (d == NULL)
633 return 1;
634 if (0 == port)
635 {
636 const union MHD_DaemonInfo *dinfo;
637
638 dinfo = MHD_get_daemon_info (d,
639 MHD_DAEMON_INFO_BIND_PORT);
640 if ( (NULL == dinfo) ||
641 (0 == dinfo->port) )
642 mhdErrorExitDesc ("MHD_get_daemon_info() failed");
643 port = dinfo->port;
644 }
645
646 /* First request */
647 ahc_param.rq_method = MHD_HTTP_METHOD_PUT;
648 ahc_param.rq_url = EXPECTED_URI_BASE_PATH;
649 cbc.buf = buf;
650 cbc.size = sizeof (buf);
651 cbc.pos = 0;
652 memset (cbc.buf, 0, cbc.size);
653 c = setupCURL (&cbc, port);
654 multi_reuse = NULL;
655 /* First request */
656 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
657 MHD_HTTP_BAD_REQUEST))
658 {
659 fflush (stderr);
660 if (verbose)
661 printf ("Got first expected response.\n");
662 fflush (stdout);
663 }
664 else
665 {
666 fprintf (stderr, "First request FAILED.\n");
667 fflush (stderr);
668 failed = 1;
669 }
670 /* Second request */
671 cbc.pos = 0; /* Reset buffer position */
672 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
673 MHD_HTTP_BAD_REQUEST))
674 {
675 fflush (stderr);
676 if (verbose)
677 printf ("Got second expected response.\n");
678 fflush (stdout);
679 }
680 else
681 {
682 fprintf (stderr, "Second request FAILED.\n");
683 fflush (stderr);
684 failed = 1;
685 }
686 /* Third request */
687 cbc.pos = 0; /* Reset buffer position */
688 if (NULL != multi_reuse)
689 curl_multi_cleanup (multi_reuse);
690 multi_reuse = NULL; /* Force new connection */
691 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
692 MHD_HTTP_BAD_REQUEST))
693 {
694 fflush (stderr);
695 if (verbose)
696 printf ("Got third expected response.\n");
697 fflush (stdout);
698 }
699 else
700 {
701 fprintf (stderr, "Third request FAILED.\n");
702 fflush (stderr);
703 failed = 1;
704 }
705
706 curl_easy_cleanup (c);
707 if (NULL != multi_reuse)
708 curl_multi_cleanup (multi_reuse);
709
710 MHD_stop_daemon (d);
711 return failed ? 1 : 0;
712}
713
714
715int
716main (int argc, char *const *argv)
717{
718 unsigned int errorCount = 0;
719
720 /* Test type and test parameters */
721 verbose = ! (has_param (argc, argv, "-q") ||
722 has_param (argc, argv, "--quiet") ||
723 has_param (argc, argv, "-s") ||
724 has_param (argc, argv, "--silent"));
725 oneone = ! has_in_name (argv[0], "10");
726
727 test_global_init ();
728
729 errorCount += performTest ();
730 if (errorCount != 0)
731 fprintf (stderr, "Error (code: %u)\n", errorCount);
732 test_global_cleanup ();
733 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
734}