commit 8d35a95be9c4caf1ce304e744c51cd7feda44ad5
parent 7caa8e7968cdef9f80482e16347707de728d9fcb
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Wed, 4 Dec 2024 20:00:00 +0100
add TLS tests
Diffstat:
8 files changed, 1143 insertions(+), 137 deletions(-)
diff --git a/src/tests/client_server/Makefile.am b/src/tests/client_server/Makefile.am
@@ -28,6 +28,12 @@ check_PROGRAMS = \
test_client_server \
test_postprocessor
+if MHD_ENABLE_HTTPS
+check_PROGRAMS += \
+ test_tls \
+ test_cert_tls
+endif
+
TESTS = $(check_PROGRAMS)
@@ -39,6 +45,7 @@ libmhdt_la_SOURCES = \
libtest_convenience.c \
libtest_convenience_client_request.c \
libtest_convenience_server_reply.c
+# TODO: fix flags, use configure-detected
libmhdt_la_LIBADD = \
-lpthread \
-lcurl \
@@ -47,10 +54,30 @@ libmhdt_la_LIBADD = \
test_client_server_SOURCES = \
test_client_server.c
test_client_server_LDADD = \
- libmhdt.la
+ libmhdt.la
+
+test_tls_SOURCES = \
+ test_tls.c
+test_tls_LDADD = \
+ libmhdt.la
+test_cert_tls_SOURCES = \
+ test_cert_tls.c
+test_cert_tls_LDADD = \
+ libmhdt.la
test_postprocessor_SOURCES = \
test_postprocessor.c
test_postprocessor_LDADD = \
- libmhdt.la
+ libmhdt.la
+
+# TODO: fix out-of-tree 'make check'
+EXTRA_DIST = \
+ data/root-ca.crt \
+ data/inter1-ca.crt \
+ data/inter2-ca.crt \
+ data/test-server.crt \
+ data/test-server-key.pem \
+ data/check_certs.sh \
+ data/make_chain.sh \
+ data/chain.crt
diff --git a/src/tests/client_server/libtest.c b/src/tests/client_server/libtest.c
@@ -23,12 +23,14 @@
* @brief testing harness with clients against server
* @author Christian Grothoff
*/
+#include "libtest.h"
#include <pthread.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include "libtest.h"
+#include <sys/stat.h>
+#include <curl/curl.h>
/**
* A semaphore.
@@ -419,6 +421,7 @@ cleanup:
&res));
if (! cctxs[i].status)
ret = false;
+ curl_slist_free_all (cctxs[i].pc.hosts);
}
test_check (0 == close (p[0]));
test_check (0 == close (p[1]));
@@ -481,7 +484,7 @@ MHDT_test (MHDT_ServerSetup ss_cb,
void *ss_cb_cls,
MHDT_ServerRunner run_cb,
void *run_cb_cls,
- const struct MHDT_Phase *phases)
+ struct MHDT_Phase *phases)
{
struct ServerContext ctx = {
.run_cb = run_cb,
@@ -493,8 +496,10 @@ MHDT_test (MHDT_ServerSetup ss_cb,
const char *err;
pthread_t server_phase_thr;
pthread_t server_run_thr;
- struct MHDT_PhaseContext pc;
- char base_url[128];
+ struct MHDT_PhaseContext pc_https;
+ struct MHDT_PhaseContext pc_http;
+ char base_http_url[128];
+ char base_https_url[128];
unsigned int i;
int p[2];
@@ -522,9 +527,16 @@ MHDT_test (MHDT_ServerSetup ss_cb,
sc = MHD_daemon_start (d);
if (MHD_SC_OK != sc)
{
+#ifdef FIXME_STATUS_CODE_TO_STRING_NOT_IMPLEMENTED
fprintf (stderr,
"Failed to start server: %s\n",
- err);
+ MHD_status_code_to_string_lazy (sc));
+#else
+ fprintf (stderr,
+ "Failed to start server: %d\n",
+ sc);
+#endif
+ MHD_daemon_destroy (d);
return 1;
}
}
@@ -537,11 +549,16 @@ MHDT_test (MHDT_ServerSetup ss_cb,
MHD_DAEMON_INFO_FIXED_BIND_PORT,
&info);
test_check (MHD_SC_OK == sc);
- snprintf (base_url,
- sizeof (base_url),
+ snprintf (base_http_url,
+ sizeof (base_http_url),
"http://localhost:%u/",
(unsigned int) info.v_port);
- pc.base_url = base_url;
+ snprintf (base_https_url,
+ sizeof (base_https_url),
+ "https://localhost:%u/",
+ (unsigned int) info.v_port);
+ pc_http.base_url = base_http_url;
+ pc_https.base_url = base_https_url;
}
if (0 != pthread_create (&server_phase_thr,
NULL,
@@ -551,6 +568,7 @@ MHDT_test (MHDT_ServerSetup ss_cb,
fprintf (stderr,
"Failed to start server phase thread: %s\n",
strerror (errno));
+ MHD_daemon_destroy (d);
return 77;
}
ctx.finsig = p[0];
@@ -563,19 +581,28 @@ MHDT_test (MHDT_ServerSetup ss_cb,
fprintf (stderr,
"Failed to start server run thread: %s\n",
strerror (errno));
+ MHD_daemon_destroy (d);
return 77;
}
for (i = 0; NULL != phases[i].label; i++)
{
+ struct MHDT_Phase *pi = &phases[i];
+ struct MHDT_PhaseContext *pc
+ = pi->use_tls
+ ? &pc_https
+ : &pc_http;
+ pc->phase = &phases[i];
+ pc->hosts = NULL;
fprintf (stderr,
"Running test phase '%s'\n",
- phases[i].label);
- if (! run_client_phase (&phases[i],
- &pc))
+ pi->label);
+ if (! run_client_phase (pi,
+ pc))
{
res = 1;
goto cleanup;
}
+ pc->hosts = NULL;
/* client is done with phase */
semaphore_up (&ctx.client_sem);
/* wait for server to have moved to new phase */
@@ -613,3 +640,74 @@ cleanup:
test_check (0 == close (p[1]));
return res;
}
+
+
+char *
+MHDT_load_pem (const char *name)
+{
+ char path[256];
+ int fd;
+ struct stat s;
+ char *buf;
+
+ snprintf (path,
+ sizeof (path),
+ "data/%s",
+ name);
+ fd = open (path,
+ O_RDONLY);
+ if (-1 == fd)
+ {
+ fprintf (stderr,
+ "Failed to open %s: %s\n",
+ path,
+ strerror (errno));
+ return NULL;
+ }
+ if (0 !=
+ fstat (fd,
+ &s))
+ {
+ fprintf (stderr,
+ "Failed to fstat %s: %s\n",
+ path,
+ strerror (errno));
+ (void) close (fd);
+ return NULL;
+ }
+ if (((unsigned long long) s.st_size) >= (unsigned long long) SIZE_MAX)
+ {
+ fprintf (stderr,
+ "File %s too large (%llu >= %llu bytes) to malloc()\n",
+ path,
+ (unsigned long long) s.st_size,
+ (unsigned long long) SIZE_MAX);
+ (void) close (fd);
+ return NULL;
+ }
+ buf = malloc (((size_t) s.st_size + 1));
+ if (NULL == buf)
+ {
+ fprintf (stderr,
+ "Failed to malloc(): %s\n",
+ strerror (errno));
+ (void) close (fd);
+ return NULL;
+ }
+ if (-1 ==
+ read (fd, // FIXME: read() should be called in loop to handle partial reads
+ buf,
+ (size_t) s.st_size))
+ {
+ fprintf (stderr,
+ "Failed to read %s: %s\n",
+ path,
+ strerror (errno));
+ free (buf);
+ (void) close (fd);
+ return NULL;
+ }
+ (void) close (fd);
+ buf[(size_t) s.st_size] = 0;
+ return buf;
+}
diff --git a/src/tests/client_server/libtest.h b/src/tests/client_server/libtest.h
@@ -35,6 +35,14 @@
#endif
#include "microhttpd2.h"
+
+/**
+ * A phase defines some server and client-side
+ * behaviors to execute.
+ */
+struct MHDT_Phase;
+
+
/**
* Information about the current phase.
*/
@@ -46,9 +54,21 @@ struct MHDT_PhaseContext
const char *base_url;
/**
+ * Data structure to keep around during the request because
+ * Curl.
+ */
+ struct curl_slist *hosts;
+
+ /**
* Specific client we are running.
*/
unsigned int client_id;
+
+ /**
+ * More details about the phase we are running.
+ */
+ struct MHDT_Phase *phase;
+
};
@@ -62,7 +82,102 @@ struct MHDT_PhaseContext
*/
typedef const char *
(*MHDT_ClientLogic)(const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
+
+
+struct MHDT_Phase
+{
+
+ /**
+ * Name of the phase, for debugging/logging.
+ */
+ const char *label;
+
+ /**
+ * Logic for the MHD server for this phase.
+ */
+ MHD_RequestCallback server_cb;
+
+ /**
+ * Closure for @e server_cb.
+ */
+ void *server_cb_cls;
+
+ /**
+ * Logic for the CURL client for this phase.
+ */
+ MHDT_ClientLogic client_cb;
+
+ /**
+ * Closure for @e client_cb.
+ */
+ const void *client_cb_cls;
+
+ /**
+ * How long is the phase allowed to run at most before
+ * timing out. 0 for no timeout.
+ */
+ unsigned int timeout_ms;
+
+ /**
+ * How many clients should be run in parallel.
+ * 0 to run just one client.
+ */
+ unsigned int num_clients;
+
+ /**
+ * Set to true if clients should setup the connection to use TLS.
+ */
+ bool use_tls;
+
+ /**
+ * Set to true if clients should check server cert.
+ */
+ bool check_server_cert;
+
+ /**
+ * Client certificate to present to the server, NULL for none.
+ */
+ const char *client_cert;
+
+ /**
+ * Client private key to use, NULL for none.
+ */
+ const char *client_priv;
+
+ /**
+ * Server certificate to present to the client, NULL for default.
+ */
+ const char *server_cert;
+
+ /**
+ * Server private key to use, NULL for default.
+ */
+ const char *server_priv;
+};
+
+
+/**
+ * Load PEM file from data/ folder and return data in it.
+ *
+ * @param name name of PEM file to load
+ * @return NULL on error
+ */
+char *
+MHDT_load_pem (const char *name);
+
+
+/**
+ * Run request against the root URL of the
+ * hostname given in @a cls.
+ *
+ * @param cls closure with hostname to use
+ * @param pc context for the client
+ * @return error message, NULL on success
+ */
+const char *
+MHDT_client_get_host (const void *cls,
+ struct MHDT_PhaseContext *pc);
/**
@@ -75,7 +190,7 @@ typedef const char *
*/
const char *
MHDT_client_get_root (const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
/**
@@ -90,7 +205,7 @@ MHDT_client_get_root (const void *cls,
*/
const char *
MHDT_client_get_with_query (const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
/**
@@ -104,7 +219,7 @@ MHDT_client_get_with_query (const void *cls,
*/
const char *
MHDT_client_set_header (const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
/**
@@ -119,7 +234,7 @@ MHDT_client_set_header (const void *cls,
*/
const char *
MHDT_client_expect_header (const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
/**
@@ -132,7 +247,7 @@ MHDT_client_expect_header (const void *cls,
*/
const char *
MHDT_client_put_data (const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
/**
@@ -145,7 +260,7 @@ MHDT_client_put_data (const void *cls,
*/
const char *
MHDT_client_chunk_data (const void *cls,
- const struct MHDT_PhaseContext *pc);
+ struct MHDT_PhaseContext *pc);
/**
@@ -257,53 +372,7 @@ struct MHDT_PostInstructions
const char *
MHDT_client_do_post (
const void *cls,
- const struct MHDT_PhaseContext *pc);
-
-
-/**
- * A phase defines some server and client-side
- * behaviors to execute.
- */
-struct MHDT_Phase
-{
-
- /**
- * Name of the phase, for debugging/logging.
- */
- const char *label;
-
- /**
- * Logic for the MHD server for this phase.
- */
- MHD_RequestCallback server_cb;
-
- /**
- * Closure for @e server_cb.
- */
- void *server_cb_cls;
-
- /**
- * Logic for the CURL client for this phase.
- */
- MHDT_ClientLogic client_cb;
-
- /**
- * Closure for @e client_cb.
- */
- const void *client_cb_cls;
-
- /**
- * How long is the phase allowed to run at most before
- * timing out. 0 for no timeout.
- */
- unsigned int timeout_ms;
-
- /**
- * How many clients should be run in parallel.
- * 0 to run just one client.
- */
- unsigned int num_clients;
-};
+ struct MHDT_PhaseContext *pc);
/**
@@ -559,6 +628,44 @@ MHDT_server_setup_minimal (const void *cls,
/**
+ * Initialize MHD daemon with TLS support, binding to any free port.
+ *
+ * @param cls closure
+ * @param[in,out] d daemon to initialize
+ * @return error message, NULL on success
+ */
+const char *
+MHDT_server_setup_tls (const void *cls,
+ struct MHD_Daemon *d);
+
+
+/**
+ * Initialize MHD daemon with TLS support using GnuTLS, binding to any free
+ * port.
+ *
+ * @param cls closure
+ * @param[in,out] d daemon to initialize
+ * @return error message, NULL on success
+ */
+const char *
+MHDT_server_setup_gnutls (const void *cls,
+ struct MHD_Daemon *d);
+
+
+/**
+ * Initialize MHD daemon with TLS support using OpenSSL, binding to any free
+ * port.
+ *
+ * @param cls closure
+ * @param[in,out] d daemon to initialize
+ * @return error message, NULL on success
+ */
+const char *
+MHDT_server_setup_openssl (const void *cls,
+ struct MHD_Daemon *d);
+
+
+/**
* Function that runs an MHD daemon until
* a read() against @a finsig succeeds.
*
@@ -620,6 +727,6 @@ MHDT_test (MHDT_ServerSetup ss_cb,
void *ss_cb_cls,
MHDT_ServerRunner run_cb,
void *run_cb_cls,
- const struct MHDT_Phase *phases);
+ struct MHDT_Phase *phases);
#endif
diff --git a/src/tests/client_server/libtest_convenience.c b/src/tests/client_server/libtest_convenience.c
@@ -23,12 +23,12 @@
* @brief convenience functions for libtest users
* @author Christian Grothoff
*/
+#include "libtest.h"
#include <pthread.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include "libtest.h"
#include <curl/curl.h>
@@ -54,6 +54,143 @@ MHDT_server_setup_minimal (const void *cls,
}
+/**
+ * Setup TLS at @a d for the given backend @a be.
+ *
+ * @return NULL on success, otherwise error message
+ */
+static const char *
+server_setup_tls (struct MHD_Daemon *d,
+ enum MHD_TlsBackend be)
+{
+ static const char *mem_cert =
+ "-----BEGIN CERTIFICATE-----\n\
+MIIDjTCCAnWgAwIBAgIUKkxAx2lVnvYcaNqBpJmTgXh1/VgwDQYJKoZIhvcNAQEL\n\
+BQAwVjELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxDzANBgNV\n\
+BAcMBkJvc3RvbjENMAsGA1UECgwEUm9vdDEPMA0GA1UEAwwGY2EuZ251MB4XDTI0\n\
+MTEyOTEyNDUyOFoXDTM0MTEyNzEyNDUyOFowVjELMAkGA1UEBhMCVVMxFjAUBgNV\n\
+BAgMDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcMBkJvc3RvbjENMAsGA1UECgwEUm9v\n\
+dDEPMA0GA1UEAwwGY2EuZ251MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n\
+AQEA23YSrcGIBgZf9bbzTnmYFy+4tM82kUhsVFKxWCNEMdKmhaeVvXogyd6Evq4P\n\
+NvBGdUABDtHp4pSEijrxWbn8sxddTznoT/8IOuHI0/PtwXYP/sHQ/HzekEUVKN2Z\n\
+NMbMUzQfaJyiIV5TrZlaBwHjQ+sRs8E56C3cQjkwuyjll2zDsEfmEnPimZRAL3kb\n\
+wW8VFfBcR2Id+a9xKjwlnB4eXQFAgYINoRgCtUOUxSeFgNnwkOUSqDknO6Xi47YZ\n\
+EdLlHyUnv5eX547xUkrYhfQuQwaqpGrjHf3GFoysN8P9kd2f1qsJKtQcUbF9DDeZ\n\
+6ya47X/LBO8QflMsVjb1V3oz9QIDAQABo1MwUTAdBgNVHQ4EFgQUsvdZoX3RxdN6\n\
+wrONr31SOA9Qbc4wHwYDVR0jBBgwFoAUsvdZoX3RxdN6wrONr31SOA9Qbc4wDwYD\n\
+VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAS3PyV7crGk9brqU90aML\n\
+2TWkjgzFb3/nASnpvVYiqyiV4neGiEjtDy7eVlqP6GlD2pYcVodY+ly9wNlo85/h\n\
+YfgCFFl37tMG7PpRac2qBqaSn1DpwsCb08LjRrOvoaRffWUikSoZmsYDlaCgl9nT\n\
+pGtIrz0BSoyu5mHalIZTVQOrbkNBNK6ZgnYy2iWuiLa5Z1xzKpsRBRaKJc1pcQE/\n\
+QVbPdCiyGQMPEVn/KHxitlycFoee/fA+izXVdstVwfig2DoMvrlGZvEkN1ER3Yz4\n\
+QPJ6HzOsBQL1F+YhnMCQfc2rpcwxAWf8JMy6jsCq42KGq53tkWqHyQ6Zu2SiLRYk\n\
+CA==\n\
+-----END CERTIFICATE-----";
+ static const char *mem_key =
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----\n\
+MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQJ1VSHi+akaaVYO3O\n\
+H7I0EAICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIZlNzQR1bh4IEggTI\n\
+8U86bfGmyAXXSi/R/l3G8ziZFyHrRE5Q/Q3uUW/jyUpe+S0gMRPqwW3V542ForbH\n\
+IH/Aa+KVxlwmsq0jlheCQewj9qZMQGuqa3iTl/OfCcuGMfsuQs2HsutoDMdEYuBI\n\
+6yOqNIrRvSHunZILLDpKz/AmCO6JnRiAwiSqPBixE5M+cm1qc7dy024REiW9l9K6\n\
+Hth9A0iYc94CUyUfHFj4CEkCNqk533Z2Ktkk3RQJnx5ORQG0iBJvoFiVODFKnoAk\n\
+Ge2HNrJH3bVvhQ+p8A/L4VmnWUCfcTyqgzo887WXRxORya6gcWWtrcEJGUbLh8sL\n\
+/mXFYj/0kEllIY+fHOmSx94I3GwBkQKER/CeOCIp+C392Pujgzrz23pdq20uIt3d\n\
+FCgbnIB+5IwOwQcqCkTYa1+Y5qCa6eFLgd8PXGTDyFwP4BHfG6WT/ctHQFi8vnXV\n\
+D1S726do1mA6CFE3DYmi45sf+Te2Xb346xk1GTSWtxGh9y4FblFDAWva4oTuvxPR\n\
+IDseBhXBsIqnOy1gb/5cGj0SIOQzqR1qlg4igv3UZFC8cVl+fNnngDBiX+nTYQVm\n\
+rDyxTzcX9txPSNpLyYRdNHwLGpzZAMoN46bUFnxt0cvRWN6MA7j1r0TYWBZKJ7b7\n\
+Yt/SuYsqSE0UJQEJz4QcQnlxu3qu4HJl7dOlto3fa42MWTkOcNr9XinHmKCZ9oYZ\n\
+PYNTggRGMXlqm66KmHWDqXqw9CeufprHq15SIJJR8v4SlvEZr+YlYQeHRI4E+FDA\n\
+mEFZy/U3ZL7ZHSDsEvpeBzIJkWxHobt57BIxYHE8KN0ZIz/mJZTxljacblFWnJRb\n\
+AUXTfrRZn3lGX+4WA6Biilwyxb71slCKaiz28C55Hnj1UwoUF8vNA3G2FGAX5Wk0\n\
+m3J2SoCHtJQYc/3lEC7zR9i3/F/7vgRxZMUWt/y6KRYq8ZnoQl3Eo2yvJYX/z7I6\n\
+JyqexAx3OvA+frN3rbO/o/k6w9333Smi0QxZzDM9tHn1BAgAtmyC1lizzKn7hDYK\n\
+o/eaPeatILbS0a/bHJBbP/R53keVr0hJ3MWK2nb/DV5Dl9j4Z6sHpo3P9L+Kq06y\n\
+G9q7NhBd7cxGq4AkCp+eSjqTvwgOX1PtAry00TUmzisLz8gIYutwJqbfZGL8WpR/\n\
+/wnLQXuM/tPLdQNy+PZeTQnPFwWQeZz4VgkMRhHV2xDw0mpzE+cdD204+YjHVdMH\n\
+D4MNrDlUmKM0OVoYgXd9YyLKzYVgW95GvY1X0SxTlIUuDiRv/SqRsurPFkSG457d\n\
+zmTUny1NRsnbv9bTXqt1Xewqsylyu02N1dZvjIzBnYMVYXl0r4aej1VNEXozQtWO\n\
+YRfWaZ29dXwZqUzd83ETQvhI4mZbwAlHbqm/CoyY6Vw4Am8hGa7II134lz2b3tkr\n\
+F1zBkvzzl6+HXewGOEjm+YorDMtfADiU/hkkykWq01NG3QSwk7jaKieb5Rlou53d\n\
+IXJQBw0KW5UrgbIFqMjpSZz1jdALBKsV+dw0wvCQ8BVXZm3zZpsV+0E4Z0sdj3TI\n\
+UbkFqQ6GpoxB25UUUlLZhBbtKy7dheuPBk0HowitYlo1kLVA/JiFB4qbdf5X/9Tm\n\
+XRkN+T0orEgy7rBQa7dJN9bdLj+dS5q8\n\
+-----END ENCRYPTED PRIVATE KEY-----";
+
+ if (MHD_SC_OK !=
+ MHD_DAEMON_SET_OPTIONS (
+ d,
+ MHD_D_OPTION_TLS (be)))
+ return "Failed to enable TLS!";
+ if (MHD_SC_OK !=
+ MHD_DAEMON_SET_OPTIONS (
+ d,
+ MHD_D_OPTION_TLS_CERT_KEY (mem_cert,
+ mem_key,
+ "masterword")))
+ return "Failed to enable TLS!";
+ return NULL;
+}
+
+
+const char *
+MHDT_server_setup_tls (const void *cls,
+ struct MHD_Daemon *d)
+{
+ const struct MHD_DaemonOptionAndValue *options = cls;
+ const char *err;
+
+ err = MHDT_server_setup_minimal (options,
+ d);
+ if (NULL != err)
+ return err;
+ err = server_setup_tls (d,
+ MHD_TLS_BACKEND_ANY);
+ if (NULL != err)
+ return err;
+ return NULL;
+}
+
+
+const char *
+MHDT_server_setup_gnutls (const void *cls,
+ struct MHD_Daemon *d)
+{
+ const struct MHD_DaemonOptionAndValue *options = cls;
+ const char *err;
+
+ err = MHDT_server_setup_minimal (options,
+ d);
+ if (NULL != err)
+ return err;
+ err = server_setup_tls (d,
+ MHD_TLS_BACKEND_GNUTLS);
+ if (NULL != err)
+ return err;
+ return NULL;
+}
+
+
+const char *
+MHDT_server_setup_openssl (const void *cls,
+ struct MHD_Daemon *d)
+{
+ const struct MHD_DaemonOptionAndValue *options = cls;
+ const char *err;
+
+ err = MHDT_server_setup_minimal (options,
+ d);
+ if (NULL != err)
+ return err;
+ err = server_setup_tls (d,
+ MHD_TLS_BACKEND_OPENSSL);
+ if (NULL != err)
+ return err;
+ return NULL;
+}
+
+
void
MHDT_server_run_minimal (void *cls,
int finsig,
@@ -130,7 +267,7 @@ MHDT_server_run_blocking (void *cls,
strerror (errno));
break;
}
-#if FIXME
+#ifdef FIXME
if (MHD_SC_OK !=
MHD_daemon_process_blocking (d,
1000))
diff --git a/src/tests/client_server/libtest_convenience_client_request.c b/src/tests/client_server/libtest_convenience_client_request.c
@@ -23,12 +23,12 @@
* @brief convenience functions implementing clients making requests for libtest users
* @author Christian Grothoff
*/
+#include "libtest.h"
#include <pthread.h>
#include <stdbool.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include "libtest.h"
#include <curl/curl.h>
@@ -226,29 +226,179 @@ check_status (CURL *c,
}
+/**
+ * Set the @a base_url for the @a c handle.
+ *
+ * @param[in,out] c curl handle to manipulate
+ * @param base_url base URL to set
+ * @param[in,out] pc phase context with further options
+ * @return NULL on success, error message on failure (@a c will be cleaned up in this case)
+ */
+static const char *
+set_url (CURL *c,
+ const char *base_url,
+ struct MHDT_PhaseContext *pc)
+{
+ if (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_URL,
+ base_url))
+ {
+ curl_easy_cleanup (c);
+ return "Failed to set URL";
+ }
+ if (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_VERBOSE,
+ 1))
+ {
+ curl_easy_cleanup (c);
+ return "Failed to set verbosity";
+ }
+ {
+ /* Force curl to do the request to 127.0.0.1 regardless of
+ hostname */
+ const char *host;
+ const char *end;
+ char ri[1024];
+
+ if (0 == strncasecmp (base_url,
+ "https://",
+ strlen ("https://")))
+ host = &base_url[strlen ("https://")];
+ else
+ host = &base_url[strlen ("http://")];
+ end = strchr (host, '/');
+ if (NULL == end)
+ end = host + strlen (host);
+ snprintf (ri,
+ sizeof (ri),
+ "%.*s:127.0.0.1",
+ (int) (end - host),
+ host);
+ pc->hosts = curl_slist_append (NULL,
+ ri);
+ if (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_RESOLVE,
+ pc->hosts))
+ {
+ curl_easy_cleanup (c);
+ return "Failed to override DNS";
+ }
+ }
+ if (0 == strncasecmp (base_url,
+ "https://",
+ strlen ("https://")))
+ {
+ struct MHDT_Phase *phase = pc->phase;
+
+ if (phase->check_server_cert)
+ {
+ if (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_CAINFO,
+ "data/root-ca.crt"))
+ {
+ curl_easy_cleanup (c);
+ return "Failed to override root CA";
+ }
+ }
+ else
+ {
+ /* disable certificate checking */
+ if ( (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_SSL_VERIFYPEER,
+ 0L)) ||
+ (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_SSL_VERIFYHOST,
+ 0L)) )
+ {
+ curl_easy_cleanup (c);
+ return "Failed to disable X509 server certificate checks";
+ }
+ }
+ if (NULL != phase->client_cert)
+ {
+ if (CURLE_OK !=
+ curl_easy_setopt (c,
+ CURLOPT_SSLCERT,
+ phase->client_cert))
+ {
+ curl_easy_cleanup (c);
+ return "Failed to set client certificate";
+ }
+ }
+ }
+ return NULL;
+}
+
+
+const char *
+MHDT_client_get_host (const void *cls,
+ struct MHDT_PhaseContext *pc)
+{
+ const char *host = cls;
+ const char *err;
+ size_t alen = strlen (host);
+ CURL *c;
+ size_t blen = strlen (pc->base_url);
+ char u[alen + blen + 1];
+ const char *slash = strchr (pc->base_url,
+ '/');
+ const char *colon;
+
+ if (NULL == slash)
+ return "'/' missing in base URL";
+ colon = strchr (slash,
+ ':');
+ if (NULL == colon)
+ return "':' missing in base URL";
+ snprintf (u,
+ sizeof (u),
+ "https://%s%s",
+ host,
+ colon);
+ c = curl_easy_init ();
+ if (NULL == c)
+ return "Failed to initialize Curl handle";
+ err = set_url (c,
+ u,
+ pc);
+ if (NULL != err)
+ return err;
+ PERFORM_REQUEST (c);
+ CHECK_STATUS (c,
+ MHD_HTTP_STATUS_OK);
+ curl_easy_cleanup (c);
+ return NULL;
+}
+
+
const char *
MHDT_client_get_root (
const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
const char *text = cls;
CURL *c;
+ const char *err;
DECLARE_WB (text);
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- pc->base_url))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ pc->base_url,
+ pc);
+ if (NULL != err)
+ return err;
SETUP_WB (c);
PERFORM_REQUEST (c);
- CHECK_STATUS (c, MHD_HTTP_STATUS_OK);
+ CHECK_STATUS (c,
+ MHD_HTTP_STATUS_OK);
curl_easy_cleanup (c);
CHECK_WB (text);
return NULL;
@@ -258,9 +408,10 @@ MHDT_client_get_root (
const char *
MHDT_client_get_with_query (
const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
const char *args = cls;
+ const char *err;
size_t alen = strlen (args);
CURL *c;
size_t blen = strlen (pc->base_url);
@@ -276,15 +427,11 @@ MHDT_client_get_with_query (
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
-
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- u))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ u,
+ pc);
+ if (NULL != err)
+ return err;
PERFORM_REQUEST (c);
CHECK_STATUS (c,
MHD_HTTP_STATUS_NO_CONTENT);
@@ -296,9 +443,10 @@ MHDT_client_get_with_query (
const char *
MHDT_client_set_header (
const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
const char *hdr = cls;
+ const char *err;
CURL *c;
CURLcode res;
struct curl_slist *slist;
@@ -306,14 +454,11 @@ MHDT_client_set_header (
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- pc->base_url))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ pc->base_url,
+ pc);
+ if (NULL != err)
+ return err;
slist = curl_slist_append (NULL,
hdr);
if (CURLE_OK !=
@@ -341,10 +486,11 @@ MHDT_client_set_header (
const char *
MHDT_client_expect_header (const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
#ifdef HAVE_LIBCRUL_NEW_HDR_API
const char *hdr = cls;
+ const char *err;
size_t hlen = strlen (hdr) + 1;
char key[hlen];
const char *colon = strchr (hdr, ':');
@@ -362,14 +508,11 @@ MHDT_client_expect_header (const void *cls,
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- pc->base_url))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ pc->base_url,
+ pc);
+ if (NULL != err)
+ return err;
PERFORM_REQUEST (c);
CHECK_STATUS (c,
MHD_HTTP_STATUS_NO_CONTENT);
@@ -471,9 +614,10 @@ read_cb (void *ptr,
const char *
MHDT_client_put_data (
const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
const char *text = cls;
+ const char *err;
struct ReadBuffer rb = {
.buf = text,
.len = strlen (text)
@@ -483,14 +627,11 @@ MHDT_client_put_data (
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- pc->base_url))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ pc->base_url,
+ pc);
+ if (NULL != err)
+ return err;
if (CURLE_OK !=
curl_easy_setopt (c,
CURLOPT_UPLOAD,
@@ -534,9 +675,10 @@ MHDT_client_put_data (
const char *
MHDT_client_chunk_data (
const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
const char *text = cls;
+ const char *err;
struct ReadBuffer rb = {
.buf = text,
.len = strlen (text),
@@ -547,14 +689,11 @@ MHDT_client_chunk_data (
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- pc->base_url))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ pc->base_url,
+ pc);
+ if (NULL != err)
+ return err;
if (CURLE_OK !=
curl_easy_setopt (c,
CURLOPT_UPLOAD,
@@ -590,9 +729,10 @@ MHDT_client_chunk_data (
const char *
MHDT_client_do_post (
const void *cls,
- const struct MHDT_PhaseContext *pc)
+ struct MHDT_PhaseContext *pc)
{
const struct MHDT_PostInstructions *pi = cls;
+ const char *err;
CURL *c;
struct curl_slist *request_hdr = NULL;
@@ -608,14 +748,11 @@ MHDT_client_do_post (
c = curl_easy_init ();
if (NULL == c)
return "Failed to initialize Curl handle";
- if (CURLE_OK !=
- curl_easy_setopt (c,
- CURLOPT_URL,
- pc->base_url))
- {
- curl_easy_cleanup (c);
- return "Failed to set URL for curl request";
- }
+ err = set_url (c,
+ pc->base_url,
+ pc);
+ if (NULL != err)
+ return err;
if (CURLE_OK !=
curl_easy_setopt (c,
CURLOPT_POST,
diff --git a/src/tests/client_server/libtest_convenience_server_reply.c b/src/tests/client_server/libtest_convenience_server_reply.c
@@ -25,13 +25,13 @@
* replies from the server for libtest users
* @author Christian Grothoff
*/
+#include "libtest.h"
#include <pthread.h>
#include <stdbool.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
-#include "libtest.h"
#include <curl/curl.h>
diff --git a/src/tests/client_server/test_cert_tls.c b/src/tests/client_server/test_cert_tls.c
@@ -0,0 +1,170 @@
+/*
+ This file is part of GNU libmicrohttpd
+ Copyright (C) 2016, 2024 Christian Grothoff & Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file test_tls.c
+ * @brief test with client against TLS server
+ * @author Christian Grothoff
+ */
+#include "libtest.h"
+
+
+int
+main (int argc, char *argv[])
+{
+ char *srv_certs_chain
+ = MHDT_load_pem ("chain.crt");
+ char *srv_cert_key
+ = MHDT_load_pem ("test-server-key.pem");
+ struct MHD_DaemonOptionAndValue rca_options[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_AUTO),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TLS (MHD_TLS_BACKEND_ANY),
+ MHD_D_OPTION_TLS_CERT_KEY (srv_certs_chain,
+ srv_cert_key,
+ NULL),
+ MHD_D_OPTION_TERMINATE ()
+ };
+#ifdef MHD_USE_GNUTLS
+ struct MHD_DaemonOptionAndValue rca_options_gnu[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_AUTO),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TLS (MHD_TLS_BACKEND_GNUTLS),
+ MHD_D_OPTION_TLS_CERT_KEY (srv_certs_chain,
+ srv_cert_key,
+ NULL),
+ MHD_D_OPTION_TERMINATE ()
+ };
+#endif
+#ifdef MHD_USE_OPENSSL
+ struct MHD_DaemonOptionAndValue rca_options_open[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_AUTO),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TLS (MHD_TLS_BACKEND_OPENSSL),
+ MHD_D_OPTION_TLS_CERT_KEY (srv_certs_chain,
+ srv_cert_key,
+ NULL),
+ MHD_D_OPTION_TERMINATE ()
+ };
+#endif
+ struct ServerType
+ {
+ const char *label;
+ MHDT_ServerSetup server_setup;
+ void *server_setup_cls;
+ MHDT_ServerRunner server_runner;
+ void *server_runner_cls;
+ struct MHDT_Phase phase;
+ } configs[] = {
+ {
+ .label = "certs_chain",
+ .server_setup = &MHDT_server_setup_minimal,
+ .server_setup_cls = rca_options,
+ .server_runner = &MHDT_server_run_minimal,
+ .phase = {
+ .label = "simple RCA get",
+ .server_cb = &MHDT_server_reply_text,
+ .server_cb_cls = (void *) "Hello world",
+ .client_cb = &MHDT_client_get_host,
+ .client_cb_cls = "localhost",
+ .timeout_ms = 2500,
+ .use_tls = true,
+ .check_server_cert = true
+ }
+
+
+ },
+#ifdef MHD_USE_GNUTLS
+ {
+ .label = "certs_chain",
+ .server_setup = &MHDT_server_setup_minimal,
+ .server_setup_cls = rca_options_gnu,
+ .server_runner = &MHDT_server_run_minimal,
+ .phase = {
+ .label = "simple RCA get",
+ .server_cb = &MHDT_server_reply_text,
+ .server_cb_cls = (void *) "Hello world",
+ .client_cb = &MHDT_client_get_host,
+ .client_cb_cls = "localhost",
+ .timeout_ms = 2500,
+ .use_tls = true,
+ .check_server_cert = true
+ }
+
+
+ },
+#endif
+#ifdef MHD_USE_OPENSSL
+ {
+ .label = "certs_chain",
+ .server_setup = &MHDT_server_setup_minimal,
+ .server_setup_cls = rca_options_open,
+ .server_runner = &MHDT_server_run_minimal,
+ .phase = {
+ .label = "simple RCA get",
+ .server_cb = &MHDT_server_reply_text,
+ .server_cb_cls = (void *) "Hello world",
+ .client_cb = &MHDT_client_get_host,
+ .client_cb_cls = "localhost",
+ .timeout_ms = 2500,
+ .use_tls = true,
+ .check_server_cert = true
+ }
+
+
+ },
+#endif
+ {
+ .label = "END"
+ }
+ };
+ unsigned int i;
+ int ret = 0;
+
+ (void) argc; /* Unused. Silence compiler warning. */
+ (void) argv; /* Unused. Silence compiler warning. */
+
+ for (i = 0; NULL != configs[i].server_setup; i++)
+ {
+ struct ServerType *st = &configs[i];
+ struct MHDT_Phase phases[2] = {
+ st->phase
+ };
+ fprintf (stderr,
+ "Running TLS tests with server setup '%s'\n",
+ st->label);
+ ret = MHDT_test (st->server_setup,
+ st->server_setup_cls,
+ st->server_runner,
+ st->server_runner_cls,
+ phases);
+ if (0 != ret)
+ {
+ fprintf (stderr,
+ "Test failed with server of type '%s' (%u)\n",
+ st->label,
+ i);
+ break;
+ }
+ }
+ free (srv_cert_key);
+ free (srv_certs_chain);
+ return ret;
+}
diff --git a/src/tests/client_server/test_tls.c b/src/tests/client_server/test_tls.c
@@ -0,0 +1,330 @@
+/*
+ This file is part of GNU libmicrohttpd
+ Copyright (C) 2016, 2024 Christian Grothoff & Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/**
+ * @file test_tls.c
+ * @brief test with client against TLS server
+ * @author Christian Grothoff
+ */
+#include "libtest.h"
+
+
+int
+main (int argc, char *argv[])
+{
+ struct MHD_DaemonOptionAndValue thread1select[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_SELECT),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue thread2select[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_SELECT),
+ MHD_D_OPTION_WM_WORKER_THREADS (2),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue thread1poll[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_POLL),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue thread2poll[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_POLL),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue thread1epoll[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_EPOLL),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue thread2epoll[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_EPOLL),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue thread1auto[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_AUTO),
+ MHD_D_OPTION_WM_WORKER_THREADS (1),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct MHD_DaemonOptionAndValue external0auto[] = {
+ MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_AUTO),
+ MHD_D_OPTION_WM_EXTERNAL_PERIODIC (),
+ MHD_D_OPTION_TERMINATE ()
+ };
+ struct ServerType
+ {
+ const char *label;
+ MHDT_ServerSetup server_setup;
+ void *server_setup_cls;
+ MHDT_ServerRunner server_runner;
+ void *server_runner_cls;
+ } configs[] = {
+#ifdef MHD_USE_SELECT
+ {
+ .label = "single threaded select",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread1select,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+ {
+ .label = "multi-threaded select",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread2select,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#if MHD_USE_GNUTLS
+ {
+ .label = "multi-threaded select, forcing GnuTLS",
+ .server_setup = &MHDT_server_setup_gnutls,
+ .server_setup_cls = thread2select,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#endif
+#endif
+#ifdef MHD_USE_POLL
+ {
+ .label = "single threaded poll",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread1poll,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+ {
+ .label = "multi-threaded poll",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread2poll,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#if MHD_USE_GNUTLS
+ {
+ .label = "multi-threaded poll, forcing GnuTLS",
+ .server_setup = &MHDT_server_setup_gnutls,
+ .server_setup_cls = thread2poll,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#endif
+#endif
+#if MHD_USE_EPOLL
+ {
+ .label = "single threaded epoll",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread1epoll,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+ {
+ .label = "multi-threaded epoll",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread2epoll,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#if MHD_USE_GNUTLS
+ {
+ .label = "multi-threaded epoll, forcing GnuTLS",
+ .server_setup = &MHDT_server_setup_gnutls,
+ .server_setup_cls = thread2epoll,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#endif
+#endif
+ {
+ .label = "auto-selected mode, single threaded",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = thread1auto,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#if MHD_USE_GNUTLS
+ {
+ .label = "auto-selected mode, single threaded, forcing GnuTLS",
+ .server_setup = &MHDT_server_setup_gnutls,
+ .server_setup_cls = thread1auto,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#endif
+#if MHD_USE_OPENSSL
+ {
+ .label = "auto-selected mode, single threaded, forcing OpenSSL",
+ .server_setup = &MHDT_server_setup_openssl,
+ .server_setup_cls = thread1auto,
+ .server_runner = &MHDT_server_run_minimal,
+ },
+#endif
+#if 1
+ /* FIXME: remove once MHD_daemon_process_blocking
+ has been implemented */
+ {
+ .label = "END"
+ },
+#endif
+ {
+ .label = "auto-selected external event loop mode, no threads",
+ .server_setup = &MHDT_server_setup_tls,
+ .server_setup_cls = external0auto,
+ .server_runner = &MHDT_server_run_blocking,
+ },
+ {
+ .label = "END"
+ }
+ };
+ struct MHDT_Phase phases[] = {
+ {
+ .label = "simple get",
+ .server_cb = &MHDT_server_reply_text,
+ .server_cb_cls = (void *) "Hello world",
+ .client_cb = &MHDT_client_get_root,
+ .client_cb_cls = "Hello world",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ {
+ .label = "GET with sendfile",
+ .server_cb = &MHDT_server_reply_file,
+ .server_cb_cls = (void *) "Hello world",
+ .client_cb = &MHDT_client_get_root,
+ .client_cb_cls = "Hello world",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ {
+ .label = "client PUT with content-length",
+ .server_cb = &MHDT_server_reply_check_upload,
+ .server_cb_cls = (void *) "simple-upload-value",
+ .client_cb = &MHDT_client_put_data,
+ .client_cb_cls = "simple-upload-value",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ {
+ .label = "client PUT with 2 chunks",
+ .server_cb = &MHDT_server_reply_check_upload,
+ .server_cb_cls = (void *) "chunky-upload-value",
+ .client_cb = &MHDT_client_chunk_data,
+ .client_cb_cls = "chunky-upload-value",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ {
+ .label = "client request with custom header",
+ .server_cb = &MHDT_server_reply_check_header,
+ .server_cb_cls = (void *) "C-Header:testvalue",
+ .client_cb = &MHDT_client_set_header,
+ .client_cb_cls = "C-Header:testvalue",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ {
+ .label = "server response with custom header",
+ .server_cb = &MHDT_server_reply_with_header,
+ .server_cb_cls = (void *) "X-Header:testvalue",
+ .client_cb = &MHDT_client_expect_header,
+ .client_cb_cls = "X-Header:testvalue",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ {
+ .label = "URL with query parameters 1",
+ .server_cb = &MHDT_server_reply_check_query,
+ .server_cb_cls = (void *) "a=b&c",
+ .client_cb = &MHDT_client_get_with_query,
+ .client_cb_cls = "?a=b&c",
+ .timeout_ms = 5000,
+ .num_clients = 4,
+ .use_tls = true
+ },
+ {
+ .label = "URL with query parameters 2",
+ .server_cb = &MHDT_server_reply_check_query,
+ .server_cb_cls = (void *) "a=b&c", /* a => b, c => NULL */
+ .client_cb = &MHDT_client_get_with_query,
+ .client_cb_cls = "?c&a=b",
+ .timeout_ms = 5000,
+ .num_clients = 1,
+ .use_tls = true
+ },
+ {
+ .label = "URL with query parameters 3",
+ .server_cb = &MHDT_server_reply_check_query,
+ .server_cb_cls = (void *) "a=&c", /* a => "", c => NULL */
+ .client_cb = &MHDT_client_get_with_query,
+ .client_cb_cls = "?c&a=",
+ .timeout_ms = 5000,
+ .num_clients = 1,
+ .use_tls = true
+ },
+ {
+ .label = "URL with query parameters 4",
+ .server_cb = &MHDT_server_reply_check_query,
+ .server_cb_cls = (void *) "a=", /* a => "" */
+ .client_cb = &MHDT_client_get_with_query,
+ .client_cb_cls = "?a=",
+ .timeout_ms = 5000,
+ .num_clients = 1,
+ .use_tls = true
+ },
+ {
+ .label = "URL with query parameters 5",
+ .server_cb = &MHDT_server_reply_check_query,
+ .server_cb_cls = (void *) "a=b", /* a => "b" */
+ .client_cb = &MHDT_client_get_with_query,
+ .client_cb_cls = "?a=b",
+ .timeout_ms = 5000,
+ .num_clients = 1,
+ .use_tls = true
+ },
+ {
+ .label = "chunked response get",
+ .server_cb = &MHDT_server_reply_chunked_text,
+ .server_cb_cls = (void *) "Hello world",
+ .client_cb = &MHDT_client_get_root,
+ .client_cb_cls = "Hello world",
+ .timeout_ms = 2500,
+ .use_tls = true
+ },
+ // TODO: chunked download
+ {
+ .label = NULL,
+ },
+ };
+ unsigned int i;
+ int ret = 0;
+
+ (void) argc; /* Unused. Silence compiler warning. */
+ (void) argv; /* Unused. Silence compiler warning. */
+
+ for (i = 0; NULL != configs[i].server_setup; i++)
+ {
+ fprintf (stderr,
+ "Running TLS tests with server setup '%s'\n",
+ configs[i].label);
+ ret = MHDT_test (configs[i].server_setup,
+ configs[i].server_setup_cls,
+ configs[i].server_runner,
+ configs[i].server_runner_cls,
+ phases);
+ if (0 != ret)
+ {
+ fprintf (stderr,
+ "Test failed with server of type '%s' (%u)\n",
+ configs[i].label,
+ i);
+ break;
+ }
+ }
+ return ret;
+}