gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] 05/06: test_parse_cookies: rewritten


From: gnunet
Subject: [libmicrohttpd] 05/06: test_parse_cookies: rewritten
Date: Mon, 19 Dec 2022 16:18:02 +0100

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a commit to branch master
in repository libmicrohttpd.

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

    test_parse_cookies: rewritten
    
    Reused the same connection with the server.
    Added more flexible checks.
---
 src/testcurl/Makefile.am          |    8 +-
 src/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
index cc685d3b..010ec2ef 100644
--- 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
index d02a2b76..987ddbf4 100644
--- 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 */
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]