libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 38b46a2fd1cf24270e6deab2bb64c381938b95a9
parent 2a71dbd38f47cb067e61b681d7ac5dd39d26b754
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Mon, 28 Nov 2022 18:53:02 +0300

test_parse_cookies: rewritten

Reused the same connection with the server.
Added more flexible checks.

Diffstat:
Msrc/testcurl/Makefile.am | 8++++----
Msrc/testcurl/test_parse_cookies.c | 1445++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
2 files changed, 1062 insertions(+), 391 deletions(-)

diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am @@ -145,7 +145,7 @@ check_PROGRAMS = \ if ENABLE_COOKIE check_PROGRAMS += \ test_parse_cookies \ - test_parse_cookies_invalid + test_parse_cookies_nonstrict endif if HEAVY_TESTS @@ -468,10 +468,10 @@ test_process_headers_SOURCES = \ test_process_headers.c mhd_has_in_name.h test_parse_cookies_SOURCES = \ - test_parse_cookies.c mhd_has_in_name.h + test_parse_cookies.c mhd_has_in_name.h mhd_has_param.h -test_parse_cookies_invalid_SOURCES = \ - test_parse_cookies.c mhd_has_in_name.h +test_parse_cookies_nonstrict_SOURCES = \ + $(test_parse_cookies_SOURCES) test_process_arguments_SOURCES = \ test_process_arguments.c mhd_has_in_name.h diff --git a/src/testcurl/test_parse_cookies.c b/src/testcurl/test_parse_cookies.c @@ -1,14 +1,14 @@ /* - This file is part of libmicrohttpd + This file is part of GNU libmicrohttpd Copyright (C) 2007 Christian Grothoff - Copyright (C) 2014-2022 Evgeny Grin (Karlson2k) + Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) - libmicrohttpd is free software; you can redistribute it and/or modify + GNU libmicrohttpd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your + by the Free Software Foundation; either version 2, or (at your option) any later version. - libmicrohttpd is distributed in the hope that it will be useful, but + GNU libmicrohttpd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -22,522 +22,1193 @@ /** * @file test_parse_cookies.c * @brief Testcase for HTTP cookie parsing - * @author Christian Grothoff * @author Karlson2k (Evgeny Grin) + * @author Christian Grothoff */ -#include "MHD_config.h" +#include "mhd_options.h" #include "platform.h" #include <curl/curl.h> #include <microhttpd.h> #include <stdlib.h> -#include <stdio.h> #include <string.h> #include <time.h> -#include "mhd_has_in_name.h" -#ifndef WINDOWS +#ifndef _WIN32 +#include <sys/socket.h> #include <unistd.h> #endif -static int use_invalid; +#include "mhd_has_param.h" +#include "mhd_has_in_name.h" -struct CBC -{ - char *buf; - size_t pos; - size_t size; -}; +#ifndef MHD_STATICSTR_LEN_ +/** + * Determine length of static string / macro strings at compile time. + */ +#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) +#endif /* ! MHD_STATICSTR_LEN_ */ -static size_t -copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +#ifndef CURL_VERSION_BITS +#define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z)) +#endif /* ! CURL_VERSION_BITS */ +#ifndef CURL_AT_LEAST_VERSION +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z)) +#endif /* ! CURL_AT_LEAST_VERSION */ + +#ifndef _MHD_INSTRMACRO +/* Quoted macro parameter */ +#define _MHD_INSTRMACRO(a) #a +#endif /* ! _MHD_INSTRMACRO */ +#ifndef _MHD_STRMACRO +/* Quoted expanded macro parameter */ +#define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a) +#endif /* ! _MHD_STRMACRO */ + +#if defined(HAVE___FUNC__) +#define externalErrorExit(ignore) \ + _externalErrorExit_func (NULL, __func__, __LINE__) +#define externalErrorExitDesc(errDesc) \ + _externalErrorExit_func (errDesc, __func__, __LINE__) +#define libcurlErrorExit(ignore) \ + _libcurlErrorExit_func (NULL, __func__, __LINE__) +#define libcurlErrorExitDesc(errDesc) \ + _libcurlErrorExit_func (errDesc, __func__, __LINE__) +#define mhdErrorExit(ignore) \ + _mhdErrorExit_func (NULL, __func__, __LINE__) +#define mhdErrorExitDesc(errDesc) \ + _mhdErrorExit_func (errDesc, __func__, __LINE__) +#define checkCURLE_OK(libcurlcall) \ + _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ + __func__, __LINE__) +#elif defined(HAVE___FUNCTION__) +#define externalErrorExit(ignore) \ + _externalErrorExit_func (NULL, __FUNCTION__, __LINE__) +#define externalErrorExitDesc(errDesc) \ + _externalErrorExit_func (errDesc, __FUNCTION__, __LINE__) +#define libcurlErrorExit(ignore) \ + _libcurlErrorExit_func (NULL, __FUNCTION__, __LINE__) +#define libcurlErrorExitDesc(errDesc) \ + _libcurlErrorExit_func (errDesc, __FUNCTION__, __LINE__) +#define mhdErrorExit(ignore) \ + _mhdErrorExit_func (NULL, __FUNCTION__, __LINE__) +#define mhdErrorExitDesc(errDesc) \ + _mhdErrorExit_func (errDesc, __FUNCTION__, __LINE__) +#define checkCURLE_OK(libcurlcall) \ + _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ + __FUNCTION__, __LINE__) +#else +#define externalErrorExit(ignore) _externalErrorExit_func (NULL, NULL, __LINE__) +#define externalErrorExitDesc(errDesc) \ + _externalErrorExit_func (errDesc, NULL, __LINE__) +#define libcurlErrorExit(ignore) _libcurlErrorExit_func (NULL, NULL, __LINE__) +#define libcurlErrorExitDesc(errDesc) \ + _libcurlErrorExit_func (errDesc, NULL, __LINE__) +#define mhdErrorExit(ignore) _mhdErrorExit_func (NULL, NULL, __LINE__) +#define mhdErrorExitDesc(errDesc) _mhdErrorExit_func (errDesc, NULL, __LINE__) +#define checkCURLE_OK(libcurlcall) \ + _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), NULL, \ + __LINE__) +#endif + + +_MHD_NORETURN static void +_externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) { - struct CBC *cbc = ctx; + fflush (stdout); + if ((NULL != errDesc) && (0 != errDesc[0])) + fprintf (stderr, "%s", errDesc); + else + fprintf (stderr, "System or external library call failed"); + if ((NULL != funcName) && (0 != funcName[0])) + fprintf (stderr, " in %s", funcName); + if (0 < lineNum) + fprintf (stderr, " at line %d", lineNum); - if (cbc->pos + size * nmemb > cbc->size) - return 0; /* overflow */ - memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); - cbc->pos += size * nmemb; - return size * nmemb; + fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, + strerror (errno)); +#ifdef MHD_WINSOCK_SOCKETS + fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); +#endif /* MHD_WINSOCK_SOCKETS */ + fflush (stderr); + exit (99); } -static enum MHD_Result -ahc_echo (void *cls, - struct MHD_Connection *connection, - const char *url, - const char *method, - const char *version, - const char *upload_data, size_t *upload_data_size, - void **req_cls) +static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; + +_MHD_NORETURN static void +_libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) { - static int ptr; - const int *puse_invalid = cls; - struct MHD_Response *response; - enum MHD_Result ret; - const char *hdr; - (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ + fflush (stdout); + if ((NULL != errDesc) && (0 != errDesc[0])) + fprintf (stderr, "%s", errDesc); + else + fprintf (stderr, "CURL library call failed"); + if ((NULL != funcName) && (0 != funcName[0])) + fprintf (stderr, " in %s", funcName); + if (0 < lineNum) + fprintf (stderr, " at line %d", lineNum); - if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) - return MHD_NO; /* unexpected method */ - if (&ptr != *req_cls) - { - *req_cls = &ptr; - return MHD_YES; - } - *req_cls = NULL; + fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, + strerror (errno)); +#ifdef MHD_WINSOCK_SOCKETS + fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); +#endif /* MHD_WINSOCK_SOCKETS */ + if (0 != libcurl_errbuf[0]) + fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); - if (! *puse_invalid) - { - hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name1"); - if ((hdr == NULL) || (0 != strcmp (hdr, "var1"))) - { - fprintf (stderr, "'name1' cookie decoded incorrectly.\n"); - exit (11); - } - hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name2"); - if ((hdr == NULL) || (0 != strcmp (hdr, "var2"))) - { - fprintf (stderr, "'name2' cookie decoded incorrectly.\n"); - exit (11); - } - hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name3"); - if ((hdr == NULL) || (0 != strcmp (hdr, ""))) - { - fprintf (stderr, "'name3' cookie decoded incorrectly.\n"); - exit (11); - } - hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name4"); - if ((hdr == NULL) || (0 != strcmp (hdr, "var4 with spaces"))) - { - fprintf (stderr, "'name4' cookie decoded incorrectly.\n"); - exit (11); - } - hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name5"); - if ((hdr == NULL) || (0 != strcmp (hdr, "var_with_=_char"))) - { - fprintf (stderr, "'name5' cookie decoded incorrectly.\n"); - exit (11); - } - if (5 != MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, - NULL, NULL)) - { - fprintf (stderr, "The total number of cookie is not five.\n"); - exit (12); - } - } + fflush (stderr); + exit (99); +} + + +_MHD_NORETURN static void +_mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) +{ + fflush (stdout); + if ((NULL != errDesc) && (0 != errDesc[0])) + fprintf (stderr, "%s", errDesc); else - { - if (0 != MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, - NULL, NULL)) - { - fprintf (stderr, "The total number of cookie is not zero.\n"); - exit (12); - } - } - response = MHD_create_response_from_buffer_copy (strlen (url), - url); - ret = MHD_queue_response (connection, MHD_HTTP_OK, response); - MHD_destroy_response (response); - if (ret == MHD_NO) - abort (); - return ret; + fprintf (stderr, "MHD unexpected error"); + if ((NULL != funcName) && (0 != funcName[0])) + fprintf (stderr, " in %s", funcName); + if (0 < lineNum) + fprintf (stderr, " at line %d", lineNum); + + fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, + strerror (errno)); +#ifdef MHD_WINSOCK_SOCKETS + fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); +#endif /* MHD_WINSOCK_SOCKETS */ + + fflush (stderr); + exit (8); } -/* Re-use the same port for all checks */ -static uint16_t port; +/* Could be increased to facilitate debugging */ +#define TIMEOUTS_VAL 5 -static unsigned int -testExternalGet (int test_number) +#define EXPECTED_URI_BASE_PATH "/" + +#define URL_SCHEME "http:/" "/" + +#define URL_HOST "127.0.0.1" + +#define URL_SCHEME_HOST URL_SCHEME URL_HOST + +#define PAGE \ + "<html><head><title>libmicrohttpd test page</title></head>" \ + "<body>Success!</body></html>" + + +#ifndef MHD_STATICSTR_LEN_ +/** + * Determine length of static string / macro strings at compile time. + */ +#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) +#endif /* ! MHD_STATICSTR_LEN_ */ + + +struct strct_str_len { - struct MHD_Daemon *d; - CURL *c; - char buf[2048]; - struct CBC cbc; - CURLM *multi; - CURLMcode mret; - fd_set rs; - fd_set ws; - fd_set es; - MHD_socket maxsock; -#ifdef MHD_WINSOCK_SOCKETS - int maxposixs; /* Max socket number unused on W32 */ -#else /* MHD_POSIX_SOCKETS */ -#define maxposixs maxsock -#endif /* MHD_POSIX_SOCKETS */ - int running; - struct CURLMsg *msg; - time_t start; - struct timeval tv; + const char *str; + const size_t len; +}; - multi = NULL; - cbc.buf = buf; - cbc.size = 2048; - cbc.pos = 0; - d = MHD_start_daemon (MHD_USE_ERROR_LOG, - port, NULL, NULL, &ahc_echo, &use_invalid, - MHD_OPTION_END); - if (d == NULL) - return 256; - if (0 == port) +#define STR_LEN_(str) {str, MHD_STATICSTR_LEN_(str)} +#define STR_NULL_ {NULL, 0} + +struct strct_cookie +{ + struct strct_str_len name; + struct strct_str_len value; +}; + +#define COOKIE_(name,value) {STR_LEN_(name), STR_LEN_(value)} +#define COOKIE_NULL {STR_NULL_, STR_NULL_} + +struct strct_test_data +{ + unsigned int line_num; + const char *header_str; + unsigned int num_cookies_non_strict; + unsigned int num_cookies_strict; + struct strct_cookie cookies[5]; +}; + +static const struct strct_test_data test_data[] = { { - const union MHD_DaemonInfo *dinfo; - dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); - if ((NULL == dinfo) || (0 == dinfo->port) ) + __LINE__, + "name1=var1; name2=var2; name3=; " \ + "name4=\"var4 with spaces\"; " \ + "name5=var_with_=_char", + 5, + 0, { - MHD_stop_daemon (d); return 32; + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - port = dinfo->port; - } - c = curl_easy_init (); - curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world"); - curl_easy_setopt (c, CURLOPT_PORT, (long) port); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); - if (! use_invalid) + }, { - if (0 == test_number) + __LINE__, + "name1=var1;name2=var2;name3=;" \ + "name4=\"var4 with spaces\";" \ + "name5=var_with_=_char", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1; name2=var2; name3=; " \ - "name4=\"var4 with spaces\"; " \ - "name5=var_with_=_char"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (1 == test_number) + }, + { + __LINE__, + "name1=var1; name2=var2; name3=; " \ + "name4=\"var4 with spaces\"; " \ + "name5=var_with_=_char\t \t", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1;name2=var2;name3=;" \ - "name4=\"var4 with spaces\";" \ - "name5=var_with_=_char"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (2 == test_number) + }, + { + __LINE__, + "name1=var1;;name2=var2;;name3=;;" \ + "name4=\"var4 with spaces\";;" \ + "name5=var_with_=_char;\t \t", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1; name2=var2; name3=; " \ - "name4=\"var4 with spaces\"; " \ - "name5=var_with_=_char\t \t"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (3 == test_number) + }, + { + __LINE__, + "name3=; name1=var1; name2=var2; " \ + "name5=var_with_=_char;" \ + "name4=\"var4 with spaces\"", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1;;name2=var2;;name3=;;" \ - "name4=\"var4 with spaces\";;" \ - "name5=var_with_=_char;\t \t"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (4 == test_number) + }, + { + __LINE__, + "name2=var2; name1=var1; " \ + "name5=var_with_=_char; name3=; " \ + "name4=\"var4 with spaces\";", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1 ;name2=var2 ;name3= ;" \ - "name4=\"var4 with spaces\" ;" \ - "name5=var_with_=_char ;"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (5 == test_number) + }, + { + __LINE__, + "name2=var2; name1=var1; " \ + "name5=var_with_=_char; " \ + "name4=\"var4 with spaces\"; name3=", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name3=; name1=var1; name2=var2; " \ - "name5=var_with_=_char;" \ - "name4=\"var4 with spaces\""); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (6 == test_number) + }, + { + __LINE__, + "name2=var2; name1=var1; " \ + "name4=\"var4 with spaces\"; " \ + "name5=var_with_=_char; name3=;", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name2=var2; name1=var1; " \ - "name5=var_with_=_char; name3=; " \ - "name4=\"var4 with spaces\";"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (7 == test_number) + }, + { + __LINE__, + ";;;;;;;;name1=var1; name2=var2; name3=; " \ + "name4=\"var4 with spaces\"; " \ + "name5=var_with_=_char", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name2=var2; name1=var1; " \ - "name5=var_with_=_char; " \ - "name4=\"var4 with spaces\"; name3="); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (8 == test_number) + }, + { + __LINE__, + "name1=var1; name2=var2; name3=; " \ + "name4=\"var4 with spaces\"; ; ; ; ; " \ + "name5=var_with_=_char", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name2=var2; name1=var1; " \ - "name4=\"var4 with spaces\"; " \ - "name5=var_with_=_char; name3=;"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (9 == test_number) + }, + { + __LINE__, + "name1=var1; name2=var2; name3=; " \ + "name4=\"var4 with spaces\"; " \ + "name5=var_with_=_char;;;;;;;;", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - ";;;;;;;;name1=var1; name2=var2; name3=; " \ - "name4=\"var4 with spaces\"; " \ - "name5=var_with_=_char"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (10 == test_number) + }, + { + __LINE__, + "name1=var1; name2=var2; " \ + "name4=\"var4 with spaces\"" \ + "name5=var_with_=_char; ; ; ; ; name3=", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1; name2=var2; name3=; " \ - "name4=\"var4 with spaces\"; ; ; ; ; " \ - "name5=var_with_=_char"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (11 == test_number) + }, + { + __LINE__, + "name5=var_with_=_char ;" \ + "name1=var1; name2=var2; name3=; " \ + "name4=\"var4 with spaces\" ", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1; name2=var2; name3=; " \ - "name4=\"var4 with spaces\"; " \ - "name5=var_with_=_char;;;;;;;;"); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (12 == test_number) + }, + { + __LINE__, + "name5=var_with_=_char; name4=\"var4 with spaces\";" \ + "name1=var1; name2=var2; name3=", + 5, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name1=var1; name2=var2; " \ - "name4=\"var4 with spaces\"" \ - "name5=var_with_=_char; ; ; ; ; name3="); + COOKIE_ ("name1", "var1"), + COOKIE_ ("name2", "var2"), + COOKIE_ ("name3", ""), + COOKIE_ ("name4", "var4 with spaces"), + COOKIE_ ("name5", "var_with_=_char") } - else if (13 == test_number) + }, + { + __LINE__, + "", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name5=var_with_=_char ;" \ - "name1=var1; name2=var2; name3=; " \ - "name4=\"var4 with spaces\" "); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (14 == test_number) + }, + { + __LINE__, + " ", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "name5=var_with_=_char; name4=\"var4 with spaces\";" \ - "name1=var1; name2=var2; name3="); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - } - else + }, { - if (0 == test_number) + __LINE__, + "\t", + 0, + 0, { - (void) 0; /* No cookie */ + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (1 == test_number) + }, + { + __LINE__, + "var=,", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - ""); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (2 == test_number) + }, + { + __LINE__, + "var=\"\\ \"", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - " "); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (3 == test_number) + }, + { + __LINE__, + "var=value space", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "\t"); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (4 == test_number) + }, + { + __LINE__, + "var=value\ttab", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "var=,"); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (5 == test_number) + }, + { + __LINE__, + "=", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "var=\"\\ \""); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (6 == test_number) + }, + { + __LINE__, + "====", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "var=value space"); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (7 == test_number) + }, + { + __LINE__, + ";=", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "var=value\ttab"); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (8 == test_number) + }, + { + __LINE__, + "var", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "="); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (9 == test_number) + }, + { + __LINE__, + "=;", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - "===="); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (10 == test_number) + }, + { + __LINE__, + "= ;", + 0, + 0, + { + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL + } + }, + { + __LINE__, + ";= ;", + 0, + 0, { - curl_easy_setopt (c, CURLOPT_COOKIE, - ";="); + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL, + COOKIE_NULL } - else if (11 == test_number) + } +}; + +/* Global parameters */ +static int verbose; +static int oneone; /**< If false use HTTP/1.0 for requests*/ +static int use_non_strict; + +static void +test_global_init (void) +{ + libcurl_errbuf[0] = 0; + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + externalErrorExit (); +} + + +static void +test_global_cleanup (void) +{ + curl_global_cleanup (); +} + + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + + +static size_t +copyBuffer (void *ptr, + size_t size, + size_t nmemb, + void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + + +struct ahc_cls_type +{ + const char *rq_method; + const char *rq_url; + const struct strct_test_data *check; +}; + + +static enum MHD_Result +ahcCheck (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **req_cls) +{ + static int marker; + struct MHD_Response *response; + enum MHD_Result ret; + struct ahc_cls_type *const param = (struct ahc_cls_type *) cls; + const unsigned int expected_num_cookies = + use_non_strict ? param->check->num_cookies_non_strict : + param->check->num_cookies_strict; + unsigned int i; + int cookie_failed; + + if (NULL == param) + mhdErrorExitDesc ("cls parameter is NULL"); + + if (oneone) + { + if (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) + mhdErrorExitDesc ("Unexpected HTTP version"); + } + else + { + if (0 != strcmp (version, MHD_HTTP_VERSION_1_0)) + mhdErrorExitDesc ("Unexpected HTTP version"); + } + + if (0 != strcmp (url, param->rq_url)) + mhdErrorExitDesc ("Unexpected URI"); + + if (NULL != upload_data) + mhdErrorExitDesc ("'upload_data' is not NULL"); + + if (NULL == upload_data_size) + mhdErrorExitDesc ("'upload_data_size' pointer is NULL"); + + if (0 != *upload_data_size) + mhdErrorExitDesc ("'*upload_data_size' value is not zero"); + + if (0 != strcmp (param->rq_method, method)) + mhdErrorExitDesc ("Unexpected request method"); + + cookie_failed = 0; + for (i = 0; i < expected_num_cookies; ++i) + { + const char *cookie_val; + size_t cookie_val_len; + const struct strct_cookie *const cookie_data = param->check->cookies + i; + if (NULL == cookie_data->name.str) + externalErrorExitDesc ("Broken test data"); + if (NULL == cookie_data->value.str) + externalErrorExitDesc ("Broken test data"); + + cookie_val = + MHD_lookup_connection_value (connection, + MHD_COOKIE_KIND, + cookie_data->name.str); + if (cookie_val == NULL) { - curl_easy_setopt (c, CURLOPT_COOKIE, - "var"); + fprintf (stderr, "'%s' cookie not found.\n", + cookie_data->name.str); + cookie_failed = 1; } - else if (12 == test_number) + else if (0 != strcmp (cookie_val, + cookie_data->value.str)) { - curl_easy_setopt (c, CURLOPT_COOKIE, - "=;"); + fprintf (stderr, "'%s' cookie decoded incorrectly.\n" + "Expected: %s\nGot: %s\n", + cookie_data->name.str, + cookie_data->value.str, + cookie_val); + cookie_failed = 1; } - else if (13 == test_number) + else if (MHD_YES != + MHD_lookup_connection_value_n (connection, + MHD_COOKIE_KIND, + cookie_data->name.str, + cookie_data->name.len, + &cookie_val, &cookie_val_len)) { - curl_easy_setopt (c, CURLOPT_COOKIE, - "= ;"); + fprintf (stderr, "'%s' (length %lu) cookie not found.\n", + cookie_data->name.str, + (unsigned long) cookie_data->name.len); + cookie_failed = 1; } - else if (14 == test_number) + else { - curl_easy_setopt (c, CURLOPT_COOKIE, - ";= ;"); + if (cookie_data->value.len != cookie_val_len) + { + fprintf (stderr, "'%s' (length %lu) cookie has wrong value length.\n" + "Expected: %lu\nGot: %lu\n", + cookie_data->name.str, + (unsigned long) cookie_data->name.len, + (unsigned long) cookie_data->value.len, + (unsigned long) cookie_val_len); + cookie_failed = 1; + } + else if (0 != memcmp (cookie_val, cookie_data->value.str, cookie_val_len)) + { + fprintf (stderr, "'%s' (length %lu) cookie has wrong value.\n" + "Expected: %.*s\nGot: %.*s\n", + cookie_data->name.str, + (unsigned long) cookie_data->name.len, + (int) cookie_data->value.len, cookie_data->value.str, + (int) cookie_val_len, cookie_val); + cookie_failed = 1; + } } } + if (((int) expected_num_cookies) != + MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, NULL, NULL)) + { + fprintf (stderr, "Wrong total number of cookies.\n" + "Expected: %u\nGot: %d\n", + expected_num_cookies, + MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, NULL, + NULL)); + cookie_failed = 1; + } + if (cookie_failed) + return MHD_NO; /* Break connection */ + + if (&marker != *req_cls) + { + *req_cls = &marker; + return MHD_YES; + } + *req_cls = NULL; + + response = + MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), + PAGE); + if (NULL == response) + mhdErrorExitDesc ("Failed to create response"); + + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + if (MHD_YES != ret) + mhdErrorExitDesc ("Failed to queue response"); - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); - /* NOTE: use of CONNECTTIMEOUT without also - setting NOSIGNAL results in really weird - crashes on my system! */ - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); + return ret; +} + + +static int +libcurl_debug_cb (CURL *handle, + curl_infotype type, + char *data, + size_t size, + void *userptr) +{ + static const char excess_mark[] = "Excess found"; + static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark); + (void) handle; + (void) userptr; - multi = curl_multi_init (); - if (multi == NULL) +#ifdef _DEBUG + switch (type) { - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 512; + case CURLINFO_TEXT: + fprintf (stderr, "* %.*s", (int) size, data); + break; + case CURLINFO_HEADER_IN: + fprintf (stderr, "< %.*s", (int) size, data); + break; + case CURLINFO_HEADER_OUT: + fprintf (stderr, "> %.*s", (int) size, data); + break; + case CURLINFO_DATA_IN: +#if 0 + fprintf (stderr, "<| %.*s\n", (int) size, data); +#endif + break; + case CURLINFO_DATA_OUT: + case CURLINFO_SSL_DATA_IN: + case CURLINFO_SSL_DATA_OUT: + case CURLINFO_END: + default: + break; + } +#endif /* _DEBUG */ + if (CURLINFO_TEXT == type) + { + if ((size >= excess_mark_len) && + (0 == memcmp (data, excess_mark, excess_mark_len))) + mhdErrorExitDesc ("Extra data has been detected in MHD reply"); } - mret = curl_multi_add_handle (multi, c); - if (mret != CURLM_OK) + return 0; +} + + +static CURL * +setupCURL (void *cbc, uint16_t port) +{ + CURL *c; + + c = curl_easy_init (); + if (NULL == c) + libcurlErrorExitDesc ("curl_easy_init() failed"); + + if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, + &copyBuffer)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, + ((long) TIMEOUTS_VAL))) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, + (oneone) ? + CURL_HTTP_VERSION_1_1 : + CURL_HTTP_VERSION_1_0)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, + ((long) TIMEOUTS_VAL))) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, + libcurl_errbuf)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) || +#ifdef _DEBUG + (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) || +#endif /* _DEBUG */ + (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, + &libcurl_debug_cb)) || +#if CURL_AT_LEAST_VERSION (7, 19, 4) + (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) || +#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */ +#if CURL_AT_LEAST_VERSION (7, 45, 0) + (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) || +#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */ + (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) + libcurlErrorExitDesc ("curl_easy_setopt() failed"); + + if (CURLE_OK != + curl_easy_setopt (c, CURLOPT_URL, + URL_SCHEME_HOST EXPECTED_URI_BASE_PATH)) + libcurlErrorExitDesc ("Cannot set request URL"); + + return c; +} + + +static CURLcode +performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse) +{ + CURLM *multi; + time_t start; + struct timeval tv; + CURLcode ret; + + ret = CURLE_FAILED_INIT; /* will be replaced with real result */ + if (NULL != *multi_reuse) + multi = *multi_reuse; + else { - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 1024; + multi = curl_multi_init (); + if (multi == NULL) + libcurlErrorExitDesc ("curl_multi_init() failed"); + *multi_reuse = multi; } + if (CURLM_OK != curl_multi_add_handle (multi, c)) + libcurlErrorExitDesc ("curl_multi_add_handle() failed"); + start = time (NULL); - while ((time (NULL) - start < 5) && (multi != NULL)) + while (time (NULL) - start <= TIMEOUTS_VAL) { - maxsock = MHD_INVALID_SOCKET; - maxposixs = -1; + fd_set rs; + fd_set ws; + fd_set es; + MHD_socket maxMhdSk; + int maxCurlSk; + int running; + + maxMhdSk = MHD_INVALID_SOCKET; + maxCurlSk = -1; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); - curl_multi_perform (multi, &running); - mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); - if (mret != CURLM_OK) + if (NULL != multi) { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2048; + curl_multi_perform (multi, &running); + if (0 == running) + { + struct CURLMsg *msg; + int msgLeft; + int totalMsgs = 0; + do + { + msg = curl_multi_info_read (multi, &msgLeft); + if (NULL == msg) + libcurlErrorExitDesc ("curl_multi_info_read() failed"); + totalMsgs++; + if (CURLMSG_DONE == msg->msg) + ret = msg->data.result; + } while (msgLeft > 0); + if (1 != totalMsgs) + { + fprintf (stderr, + "curl_multi_info_read returned wrong " + "number of results (%d).\n", + totalMsgs); + externalErrorExit (); + } + curl_multi_remove_handle (multi, c); + multi = NULL; + } + else + { + if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) + libcurlErrorExitDesc ("curl_multi_fdset() failed"); + } } - if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) - { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 4096; + if (NULL == multi) + { /* libcurl has finished, check whether MHD still needs to perform cleanup */ + if (0 != MHD_get_timeout64s (d)) + break; /* MHD finished as well */ } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) + mhdErrorExitDesc ("MHD_get_fdset() failed"); tv.tv_sec = 0; - tv.tv_usec = 1000; - if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) + tv.tv_usec = 200000; + if (0 == MHD_get_timeout64s (d)) + tv.tv_usec = 0; + else + { + long curl_to = -1; + curl_multi_timeout (multi, &curl_to); + if (0 == curl_to) + tv.tv_usec = 0; + } +#ifdef MHD_POSIX_SOCKETS + if (maxMhdSk > maxCurlSk) + maxCurlSk = maxMhdSk; +#endif /* MHD_POSIX_SOCKETS */ + if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) { #ifdef MHD_POSIX_SOCKETS if (EINTR != errno) - { - fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", - (int) errno, __LINE__); - fflush (stderr); - exit (99); - } + externalErrorExitDesc ("Unexpected select() error"); #else if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) - { - fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", - (int) WSAGetLastError (), __LINE__); - fflush (stderr); - exit (99); - } - Sleep (1); + externalErrorExitDesc ("Unexpected select() error"); + Sleep ((unsigned long) tv.tv_usec / 1000); #endif } - curl_multi_perform (multi, &running); - if (0 == running) - { - int pending; - int curl_fine = 0; - while (NULL != (msg = curl_multi_info_read (multi, &pending))) - { - if (msg->msg == CURLMSG_DONE) - { - if (msg->data.result == CURLE_OK) - curl_fine = 1; - else - { - fprintf (stderr, - "%s failed at %s:%d: `%s'\n", - "curl_multi_perform", - __FILE__, - __LINE__, curl_easy_strerror (msg->data.result)); - abort (); - } - } - } - if (! curl_fine) - { - fprintf (stderr, "libcurl haven't returned OK code\n"); - abort (); - } - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - c = NULL; - multi = NULL; - } - MHD_run (d); + if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) + mhdErrorExitDesc ("MHD_run_from_select() failed"); + } + + return ret; +} + + +/** + * Check request result + * @param curl_code the CURL easy return code + * @param pcbc the pointer struct CBC + * @return non-zero if success, zero if failed + */ +static unsigned int +check_result (CURLcode curl_code, CURL *c, long expected_code, + struct CBC *pcbc) +{ + long code; + unsigned int ret; + + if (CURLE_OK != curl_code) + { + fflush (stdout); + if (0 != libcurl_errbuf[0]) + fprintf (stderr, "Request failed. " + "libcurl error: '%s'.\n" + "libcurl error description: '%s'.\n", + curl_easy_strerror (curl_code), + libcurl_errbuf); + else + fprintf (stderr, "Request failed. " + "libcurl error: '%s'.\n", + curl_easy_strerror (curl_code)); + fflush (stderr); + return 0; } - if (multi != NULL) + + if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) + libcurlErrorExit (); + + ret = 1; + if (expected_code != code) { - curl_multi_remove_handle (multi, c); - curl_easy_cleanup (c); - curl_multi_cleanup (multi); + fprintf (stderr, "The response has wrong HTTP code: %ld\tExpected: %ld.\n", + code, expected_code); + ret = 0; } - MHD_stop_daemon (d); - if (cbc.pos != strlen ("/hello_world")) - return 8192; - if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) - return 16384; - return 0; + else if (verbose) + printf ("The response has expected HTTP code: %ld\n", expected_code); + + if (pcbc->pos != MHD_STATICSTR_LEN_ (PAGE)) + { + fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", + (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf, + (unsigned) MHD_STATICSTR_LEN_ (PAGE)); + mhdErrorExitDesc ("Wrong returned data length"); + } + if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos)) + { + fprintf (stderr, "Got invalid response '%.*s'. ", + (int) pcbc->pos, pcbc->buf); + mhdErrorExitDesc ("Wrong returned data"); + } + fflush (stderr); + fflush (stdout); + + return ret; } -int -main (int argc, char *const *argv) +static unsigned int +testExternalPolling (void) { - unsigned int errorCount = 0; - (void) argc; /* Unused. Silent compiler warning. */ + struct MHD_Daemon *d; + uint16_t port; + struct CBC cbc; + struct ahc_cls_type ahc_param; + char buf[2048]; + CURL *c; + CURLM *multi_reuse; + size_t i; + int failed = 0; - if ((NULL == argv) || (0 == argv[0])) - return 99; - use_invalid = has_in_name (argv[0], "_invalid"); - if (0 != curl_global_init (CURL_GLOBAL_WIN32)) - return 2; if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) port = 0; else + port = 1340 + oneone ? 0 : 1 + use_non_strict ? 0 : 2; + + d = MHD_start_daemon (MHD_USE_ERROR_LOG, + port, NULL, NULL, + &ahcCheck, &ahc_param, + MHD_OPTION_STRICT_FOR_CLIENT, + (int) (use_non_strict ? 0 : 1), + MHD_OPTION_END); + if (d == NULL) + return 1; + if (0 == port) { - port = 1340; - if (use_invalid) - port += 5; + const union MHD_DaemonInfo *dinfo; + + dinfo = MHD_get_daemon_info (d, + MHD_DAEMON_INFO_BIND_PORT); + if ( (NULL == dinfo) || + (0 == dinfo->port) ) + mhdErrorExitDesc ("MHD_get_daemon_info() failed"); + port = dinfo->port; } - errorCount += testExternalGet (0); - errorCount += testExternalGet (1); - errorCount += testExternalGet (2); - errorCount += testExternalGet (3); - errorCount += testExternalGet (4); - errorCount += testExternalGet (5); - errorCount += testExternalGet (6); - errorCount += testExternalGet (7); - errorCount += testExternalGet (8); - errorCount += testExternalGet (9); - errorCount += testExternalGet (10); - errorCount += testExternalGet (11); + + ahc_param.rq_method = MHD_HTTP_METHOD_GET; + ahc_param.rq_url = EXPECTED_URI_BASE_PATH; + cbc.buf = buf; + cbc.size = sizeof (buf); + memset (cbc.buf, 0, cbc.size); + c = setupCURL (&cbc, port); + multi_reuse = NULL; + for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i) + { + cbc.pos = 0; + ahc_param.check = test_data + i; + if (CURLE_OK != + curl_easy_setopt (c, CURLOPT_COOKIE, + ahc_param.check->header_str)) + libcurlErrorExitDesc ("Cannot set request cookies"); + + if (check_result (performQueryExternal (d, c, &multi_reuse), c, + MHD_HTTP_OK, &cbc)) + { + if (verbose) + printf ("Got expected response for the check at line %u.\n", + test_data[i].line_num); + fflush (stdout); + } + else + { + fprintf (stderr, "FAILED request for the check at line %u.\n", + test_data[i].line_num); + fflush (stderr); + failed = 1; + } + } + + curl_easy_cleanup (c); + if (NULL != multi_reuse) + curl_multi_cleanup (multi_reuse); + + MHD_stop_daemon (d); + return failed ? 1 : 0; +} + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + /* Test type and test parameters */ + verbose = ! (has_param (argc, argv, "-q") || + has_param (argc, argv, "--quiet") || + has_param (argc, argv, "-s") || + has_param (argc, argv, "--silent")); + oneone = ! has_in_name (argv[0], "10"); + use_non_strict = has_in_name (argv[0], "_nonstrict"); + + test_global_init (); + + errorCount += testExternalPolling (); if (errorCount != 0) fprintf (stderr, "Error (code: %u)\n", errorCount); - curl_global_cleanup (); + + test_global_cleanup (); + return (0 == errorCount) ? 0 : 1; /* 0 == pass */ }