gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [libmicrohttpd] GNU libmicrohttpd branch master updated. 35


From: gitolite
Subject: [GNUnet-SVN] [libmicrohttpd] GNU libmicrohttpd branch master updated. 35b58f8e099f6b9f9fd9e1061e011cc8a2a0bdc1
Date: Mon, 7 Nov 2016 13:26:48 +0100 (CET)

The branch, master has been updated
       via  35b58f8e099f6b9f9fd9e1061e011cc8a2a0bdc1 (commit)
       via  9ea89671719e23e5bcff40b17a3c0fe66c047cc3 (commit)
      from  8b10b7801c17f9d589cdb4b5131e5621ee088827 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 35b58f8e099f6b9f9fd9e1061e011cc8a2a0bdc1
Author: Evgeny Grin (Karlson2k) <address@hidden>
Date:   Mon Nov 7 15:11:18 2016 +0300

    Compare threads IDs in portable and documented way.

commit 9ea89671719e23e5bcff40b17a3c0fe66c047cc3
Author: Evgeny Grin (Karlson2k) <address@hidden>
Date:   Sat Nov 5 13:43:44 2016 +0300

    Combine upgrade tests into single source file, port to platforms without 
fork()

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                         |   42 ++
 src/microhttpd/Makefile.am           |   30 +-
 src/microhttpd/test_upgrade.c        | 1070 +++++++++++++++++++++++++++++++++-
 src/microhttpd/test_upgrade_common.c |  562 ------------------
 src/microhttpd/test_upgrade_ssl.c    |  236 --------
 5 files changed, 1117 insertions(+), 823 deletions(-)
 delete mode 100644 src/microhttpd/test_upgrade_common.c
 delete mode 100644 src/microhttpd/test_upgrade_ssl.c

diff --git a/configure.ac b/configure.ac
index c8a7c3f..7a74e24 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1173,6 +1173,48 @@ AS_VAR_IF([[enable_httpupgrade]],[["yes"]],
 AM_CONDITIONAL([ENABLE_UPGRADE], [[test "x$enable_httpupgrade" = "xyes"]])
 AC_MSG_RESULT([[$enable_httpupgrade]])
 
+# Check for fork() and waitpid(). They are used for tests.
+AC_MSG_CHECKING([[for fork()]])
+AC_LINK_IFELSE(
+  [
+   AC_LANG_PROGRAM(
+     [[
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+     ]], [[
+  pid_t p = fork ();
+  if (0 == p)
+    return 1;
+     ]])
+  ], [
+   AC_DEFINE([[HAVE_FORK]], [[1]], [Define to 1 if you have the usable `fork' 
function.])
+   AC_MSG_RESULT([[yes]])
+
+   AC_MSG_CHECKING([[for waitpid()]])
+   AC_LINK_IFELSE(
+     [
+      AC_LANG_PROGRAM(
+        [[
+#include <sys/wait.h>
+        ]], [[
+     pid_t p = fork ();
+     if (0 == p)
+       return 1;
+     waitpid (p, (void*)0, 0)
+        ]])
+     ], [
+      AC_DEFINE([[HAVE_WAITPID]], [[1]], [Define to 1 if you have the usable 
`waitpid' function.])
+      AC_MSG_RESULT([[yes]])
+    ],[
+       AC_MSG_RESULT([[no]])
+    ])
+],[
+   AC_MSG_RESULT([[no]])
+])
 
 
 MHD_LIB_LDFLAGS="$MHD_LIB_LDFLAGS -export-dynamic -no-undefined"
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 81dc95c..cc48d11 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -152,10 +152,12 @@ check_PROGRAMS = \
   test_shutdown_poll \
   test_daemon
 
+if HAVE_POSIX_THREADS
 if ENABLE_UPGRADE
   check_PROGRAMS += test_upgrade
 if ENABLE_HTTPS
-  check_PROGRAMS += test_upgrade_ssl
+  check_PROGRAMS += test_upgrade_tls
+endif
 endif
 endif
 
@@ -180,14 +182,28 @@ test_daemon_LDADD = \
   $(top_builddir)/src/microhttpd/libmicrohttpd.la
 
 test_upgrade_SOURCES = \
-  test_upgrade.c
+  test_upgrade.c test_helpers.h mhd_sockets.h
+test_upgrade_CPPFLAGS = \
+  $(AM_CPPFLAGS) $(GNUTLS_CPPFLAGS)
+test_upgrade_CFLAGS = \
+  $(AM_CFLAGS) $(PTHREAD_CFLAGS)
+test_upgrade_LDFLAGS = \
+  $(GNUTLS_LDFLAGS)
 test_upgrade_LDADD = \
-  $(top_builddir)/src/microhttpd/libmicrohttpd.la
+  $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+  $(PTHREAD_LIBS)
 
-test_upgrade_ssl_SOURCES = \
-  test_upgrade_ssl.c
-test_upgrade_ssl_LDADD = \
-  $(top_builddir)/src/microhttpd/libmicrohttpd.la
+test_upgrade_tls_SOURCES = \
+  test_upgrade.c test_helpers.h mhd_sockets.h
+test_upgrade_tls_CPPFLAGS = \
+  $(AM_CPPFLAGS) $(GNUTLS_CPPFLAGS)
+test_upgrade_tls_CFLAGS = \
+  $(AM_CFLAGS) $(PTHREAD_CFLAGS)
+test_upgrade_tls_LDFLAGS = \
+  $(GNUTLS_LDFLAGS)
+test_upgrade_tls_LDADD = \
+  $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+  $(PTHREAD_LIBS)
 
 test_postprocessor_SOURCES = \
   test_postprocessor.c
diff --git a/src/microhttpd/test_upgrade.c b/src/microhttpd/test_upgrade.c
index 7258345..8b83564 100644
--- a/src/microhttpd/test_upgrade.c
+++ b/src/microhttpd/test_upgrade.c
@@ -22,30 +22,969 @@
  * @file test_upgrade.c
  * @brief  Testcase for libmicrohttpd upgrading a connection
  * @author Christian Grothoff
+ * @author Karlson2k (Evgeny Grin)
  */
 
-#include "platform.h"
-#include "microhttpd.h"
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <pthread.h>
-
+#include <stdlib.h>
+#include <stddef.h>
 #ifndef WINDOWS
 #include <unistd.h>
 #endif
+#include "mhd_options.h"
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif /* HAVE_STDBOOL_H */
 
 #include "mhd_sockets.h"
 #ifdef HAVE_NETINET_IP_H
 #include <netinet/ip.h>
 #endif /* HAVE_NETINET_IP_H */
 
-static int verbose = 0;
+#include "platform.h"
+#include "microhttpd.h"
+
 #include "test_helpers.h"
-#include "test_upgrade_common.c"
+
+#ifdef HTTPS_SUPPORT
+#include <gnutls/gnutls.h>
+#include "../testcurl/https/tls_test_keys.h"
+
+#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif /* HAVE_FORK && HAVE_WAITPID */
+#endif /* HTTPS_SUPPORT */
+
+static int verbose = 0;
+
+enum tls_tool
+{
+  TLS_CLI_NO_TOOL = 0,
+  TLS_CLI_GNUTLS,
+  TLS_CLI_OPENSSL,
+  TLS_LIB_GNUTLS
+};
+
+enum tls_tool use_tls_tool;
+
+#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
+/**
+ * Fork child that connects via GnuTLS-CLI to our @a port.  Allows us to
+ * talk to our port over a socket in @a sp without having to worry
+ * about TLS.
+ *
+ * @param location where the socket is returned
+ * @return -1 on error, otherwise PID of TLS child process
+ */
+static pid_t
+gnutlscli_connect (int *sock,
+                 uint16_t port)
+{
+  pid_t chld;
+  int sp[2];
+  char destination[30];
+
+  if (0 != socketpair (AF_UNIX,
+                       SOCK_STREAM,
+                       0,
+                       sp))
+    return -1;
+  chld = fork ();
+  if (0 != chld)
+    {
+      *sock = sp[1];
+      MHD_socket_close_chk_ (sp[0]);
+      return chld;
+    }
+  MHD_socket_close_chk_ (sp[1]);
+  (void) close (0);
+  (void) close (1);
+  dup2 (sp[0], 0);
+  dup2 (sp[0], 1);
+  MHD_socket_close_chk_ (sp[0]);
+  if (TLS_CLI_GNUTLS == use_tls_tool)
+    {
+      snprintf (destination,
+                sizeof(destination),
+                "%u",
+                (unsigned int) port);
+      execlp ("gnutls-cli",
+              "gnutls-cli",
+              "--insecure",
+              "-p",
+              destination,
+              "localhost",
+              (char *) NULL);
+    }
+  else if (TLS_CLI_OPENSSL == use_tls_tool)
+    {
+      snprintf (destination,
+                sizeof(destination),
+                "localhost:%u",
+                (unsigned int) port);
+      execlp ("openssl",
+              "openssl",
+              "s_client",
+              "-connect",
+              destination,
+              "-verify",
+              "0",
+              (char *) NULL);
+    }
+  _exit (1);
+}
+#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
+
+
+/**
+ * Wrapper structure for plain&TLS sockets
+ */
+struct wr_socket_strc
+{
+  /**
+   * Real network socket
+   */
+  MHD_socket fd;
+
+  /**
+   * Type of this socket
+   */
+  enum wr_type
+  {
+    wr_invalid = 0,
+    wr_plain = 1,
+    wr_tls = 2
+  } t;
+#ifdef HTTPS_SUPPORT
+  /**
+   * TLS credentials
+   */
+  gnutls_certificate_credentials_t tls_crd;
+
+  /**
+   * TLS session.
+   */
+  gnutls_session_t tls_s;
+
+  /**
+   * TLS handshake already succeed?
+   */
+  bool tls_connected;
+#endif
+};
+
+
+/**
+ * Pseudo type for plain&TLS sockets
+ */
+typedef struct wr_socket_strc* wr_socket;
+
+
+/**
+ * Invalid value of wr_socket
+ */
+#define WR_BAD (NULL)
+
+
+/**
+ * Get underlying real socket.
+ * @return FD of real socket
+ */
+#define wr_fd(s) ((s)->fd)
+
+
+/**
+ * Create wr_socket with plain TCP underlying socket
+ * @return created socket on success, WR_BAD otherwise
+ */
+static wr_socket wr_create_plain_sckt(void)
+{
+  wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc));
+  if (WR_BAD == s)
+    return WR_BAD;
+  s->t = wr_plain;
+  s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (MHD_INVALID_SOCKET != s->fd)
+    return s;
+  free(s);
+  return WR_BAD;
+}
+
+
+/**
+ * Create wr_socket with TLS TCP underlying socket
+ * @return created socket on success, WR_BAD otherwise
+ */
+static wr_socket wr_create_tls_sckt(void)
+{
+#ifdef HTTPS_SUPPORT
+  wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc));
+  if (WR_BAD == s)
+    return WR_BAD;
+  s->t = wr_tls;
+  s->tls_connected = 0;
+  s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (MHD_INVALID_SOCKET != s->fd)
+    {
+      if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT))
+        {
+          if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s))
+            {
+              if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials 
(&(s->tls_crd)))
+                {
+                  if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, 
GNUTLS_CRD_CERTIFICATE, s->tls_crd))
+                    {
+                      gnutls_transport_set_int (s->tls_s, (int )(s->fd));
+                      return s;
+                    }
+                  gnutls_certificate_free_credentials (s->tls_crd);
+                }
+            }
+          gnutls_deinit (s->tls_s);
+        }
+      (void)MHD_socket_close_ (s->fd);
+    }
+  free(s);
+#endif /* HTTPS_SUPPORT */
+  return WR_BAD;
+}
+
+
+/**
+ * Create wr_socket with plain TCP underlying socket
+ * from already created TCP socket.
+ * @param plain_sk real TCP socket
+ * @return created socket on success, WR_BAD otherwise
+ */
+static wr_socket wr_create_from_plain_sckt(MHD_socket plain_sk)
+{
+  wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc));
+  if (WR_BAD == s)
+    return WR_BAD;
+  s->t = wr_plain;
+  s->fd = plain_sk;
+  return s;
+}
+
+
+/**
+ * Connect socket to specified address.
+ * @param s socket to use
+ * @param addr address to connect
+ * @param length of sturcture pointed by @a addr
+ * @return zero on success, -1 otherwise.
+ */
+static int wr_connect(wr_socket s, struct sockaddr * addr, int length)
+{
+  if (0 != connect(s->fd, addr, length))
+    return -1;
+  if (wr_plain == s->t)
+    return 0;
+#ifdef HTTPS_SUPPORT
+  if (wr_tls == s->t)
+    {
+      s->tls_connected = 0;
+      return 0;
+      /* Do not try handshake here as
+       * it require processing on MHD side and
+       * when testing with "external" polling,
+       * test will call MHD processing only
+       * after return from wr_connect(). */
+      /*
+      int res = gnutls_handshake (s->tls_s);
+      if (GNUTLS_E_SUCCESS == res)
+        {
+          s->tls_connected = !0;
+          return 0;
+        }
+      if (GNUTLS_E_AGAIN == res)
+        return 0;
+       */
+    }
+#endif /* HTTPS_SUPPORT */
+  return -1;
+}
+
+#ifdef HTTPS_SUPPORT
+/* Only to be called from wr_send() and wr_recv() ! */
+static bool wr_handshake(wr_socket s)
+{
+  int res = gnutls_handshake (s->tls_s);
+  if (GNUTLS_E_SUCCESS == res)
+    s->tls_connected = !0;
+  else if (GNUTLS_E_AGAIN == res)
+    MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
+  else
+    MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
+  return s->tls_connected;
+}
+#endif /* HTTPS_SUPPORT */
+
+
+/**
+ * Send data to remote by socket.
+ * @param s the socket to use
+ * @param buf the buffer with data to send
+ * @param len the length of data in @a buf
+ * @return number of bytes were sent if succeed,
+ *         -1 if failed. Use #MHD_socket_get_error_()
+ *         to get socket error.
+ */
+static ssize_t wr_send(wr_socket s, const void *buf, size_t len)
+{
+  if (wr_plain == s->t)
+    return MHD_send_(s->fd, buf, len);
+#ifdef HTTPS_SUPPORT
+  if (wr_tls == s->t)
+    {
+      ssize_t ret;
+      if (!s->tls_connected && !wr_handshake (s))
+        return -1;
+
+      ret = gnutls_record_send (s->tls_s, buf, len);
+      if (ret > 0)
+        return ret;
+      if (GNUTLS_E_AGAIN == ret)
+        MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
+      else
+        MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
+    }
+#endif /* HTTPS_SUPPORT */
+  return -1;
+}
+
+
+/**
+ * Receive data from remote by socket.
+ * @param s the socket to use
+ * @param buf the buffer to store received data
+ * @param len the length of @a buf
+ * @return number of bytes were received if succeed,
+ *         -1 if failed. Use #MHD_socket_get_error_()
+ *         to get socket error.
+ */
+static ssize_t wr_recv(wr_socket s, void *buf, size_t len)
+{
+  if (wr_plain == s->t)
+    return MHD_recv_ (s->fd, buf, len);
+#ifdef HTTPS_SUPPORT
+  if (wr_tls == s->t)
+    {
+      ssize_t ret;
+      if (!s->tls_connected && !wr_handshake (s))
+        return -1;
+
+      ret = gnutls_record_recv (s->tls_s, buf, len);
+      if (ret > 0)
+        return ret;
+      if (GNUTLS_E_AGAIN == ret)
+        MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
+      else
+        MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
+    }
+#endif /* HTTPS_SUPPORT */
+  return -1;
+}
+
+
+/**
+ * Perform shutdown of TCP socket for plain sockets or
+ * shutdown of TLS layer for TLS sockets.
+ * @param s the socket to shutdown
+ * @param how SHUT_WR or SHUT_RDWR
+ * @return zero on succeed, -1 otherwise
+ */
+static int wr_shutdown(wr_socket s, int how)
+{
+  if (wr_plain == s->t)
+    return shutdown (s->fd, how);
+#ifdef HTTPS_SUPPORT
+  if (wr_tls == s->t)
+    {
+      ssize_t ret;
+      if (SHUT_WR == how)
+        ret = gnutls_bye (s->tls_s, GNUTLS_SHUT_WR);
+      else
+        ret = gnutls_bye (s->tls_s, GNUTLS_SHUT_RDWR);
+
+      if (GNUTLS_E_SUCCESS == ret)
+        return 0;
+    }
+#endif /* HTTPS_SUPPORT */
+  return -1;
+}
+
+
+/**
+ * Close socket and release allocated resourced
+ * @param s the socket to close
+ * @return zero on succeed, -1 otherwise
+ */
+static int wr_close(wr_socket s)
+{
+  int ret = (MHD_socket_close_(s->fd)) ? 0 : -1;
+#ifdef HTTPS_SUPPORT
+  if (wr_tls == s->t)
+    {
+      gnutls_deinit (s->tls_s);
+      gnutls_certificate_free_credentials (s->tls_crd);
+    }
+#endif /* HTTPS_SUPPORT */
+  free(s);
+  return ret;
+}
+
+
+/**
+ * Thread we use to run the interaction with the upgraded socket.
+ */
+static pthread_t pt;
+
+/**
+ * Will be set to the upgraded socket.
+ */
+static wr_socket usock;
+
+/**
+ * Thread we use to run the interaction with the upgraded socket.
+ */
+static pthread_t pt_client;
+
+/**
+ * Flag set to 1 once the test is finished.
+ */
+static int done;
+
+
+static void
+notify_completed_cb (void *cls,
+                     struct MHD_Connection *connection,
+                     void **con_cls,
+                     enum MHD_RequestTerminationCode toe)
+{
+  if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) &&
+       (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) &&
+       (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) )
+    abort ();
+  if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ()))
+    abort ();
+  free (*con_cls);
+  *con_cls = NULL;
+}
+
+
+/**
+ * Logging callback.
+ *
+ * @param cls logging closure (NULL)
+ * @param uri access URI
+ * @param connection connection handle
+ * @return #TEST_PTR
+ */
+static void *
+log_cb (void *cls,
+        const char *uri,
+        struct MHD_Connection *connection)
+{
+  pthread_t* ppth;
+  if (0 != strcmp (uri,
+                   "/"))
+    abort ();
+  ppth = (pthread_t*) malloc (sizeof(pthread_t));
+  if (NULL == ppth)
+    abort();
+  *ppth = pthread_self ();
+  return (void *) ppth;
+}
+
+
+/**
+ * Function to check that MHD properly notifies about starting
+ * and stopping.
+ *
+ * @param cls client-defined closure
+ * @param connection connection handle
+ * @param socket_context socket-specific pointer where the
+ *                       client can associate some state specific
+ *                       to the TCP connection; note that this is
+ *                       different from the "con_cls" which is per
+ *                       HTTP request.  The client can initialize
+ *                       during #MHD_CONNECTION_NOTIFY_STARTED and
+ *                       cleanup during #MHD_CONNECTION_NOTIFY_CLOSED
+ *                       and access in the meantime using
+ *                       #MHD_CONNECTION_INFO_SOCKET_CONTEXT.
+ * @param toe reason for connection notification
+ * @see #MHD_OPTION_NOTIFY_CONNECTION
+ * @ingroup request
+ */
+static void
+notify_connection_cb (void *cls,
+                      struct MHD_Connection *connection,
+                      void **socket_context,
+                      enum MHD_ConnectionNotificationCode toe)
+{
+  static int started;
+
+  switch (toe)
+  {
+  case MHD_CONNECTION_NOTIFY_STARTED:
+    if (MHD_NO != started)
+      abort ();
+    started = MHD_YES;
+    *socket_context = &started;
+    break;
+  case MHD_CONNECTION_NOTIFY_CLOSED:
+    if (MHD_YES != started)
+      abort ();
+    if (&started != *socket_context)
+      abort ();
+    *socket_context = NULL;
+    started = MHD_NO;
+    break;
+  }
+}
+
+
+/**
+ * Change socket to blocking.
+ *
+ * @param fd the socket to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+static void
+make_blocking (MHD_socket fd)
+{
+#if defined(MHD_POSIX_SOCKETS)
+  int flags;
+
+  flags = fcntl (fd, F_GETFL);
+  if (-1 == flags)
+    return;
+  if ((flags & ~O_NONBLOCK) != flags)
+    if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
+      abort ();
+#elif defined(MHD_WINSOCK_SOCKETS)
+  unsigned long flags = 1;
+
+  ioctlsocket (fd, FIONBIO, &flags);
+#endif /* MHD_WINSOCK_SOCKETS */
+
+}
+
+
+static void
+send_all (wr_socket sock,
+          const char *text)
+{
+  size_t len = strlen (text);
+  ssize_t ret;
+
+  make_blocking (wr_fd (sock));
+  for (size_t off = 0; off < len; off += ret)
+    {
+      ret = wr_send (sock,
+                       &text[off],
+                       len - off);
+      if (0 > ret)
+        {
+          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+    }
+}
+
+
+/**
+ * Read character-by-character until we
+ * get '\r\n\r\n'.
+ */
+static void
+recv_hdr (wr_socket sock)
+{
+  unsigned int i;
+  char next;
+  char c;
+  ssize_t ret;
+
+  make_blocking (wr_fd (sock));
+  next = '\r';
+  i = 0;
+  while (i < 4)
+    {
+      ret = wr_recv (sock,
+                       &c,
+                       1);
+      if (0 > ret)
+        {
+          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
+            continue;
+          abort ();
+        }
+      if (0 == ret)
+        continue;
+      if (c == next)
+        {
+          i++;
+          if (next == '\r')
+            next = '\n';
+          else
+            next = '\r';
+          continue;
+        }
+      if (c == '\r')
+        {
+          i = 1;
+          next = '\n';
+          continue;
+        }
+      i = 0;
+      next = '\r';
+    }
+}
+
+
+static void
+recv_all (wr_socket sock,
+          const char *text)
+{
+  size_t len = strlen (text);
+  char buf[len];
+  ssize_t ret;
+
+  make_blocking (wr_fd (sock));
+  for (size_t off = 0; off < len; off += ret)
+    {
+      ret = wr_recv (sock,
+                       &buf[off],
+                       len - off);
+      if (0 > ret)
+        {
+          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+    }
+  if (0 != strncmp (text, buf, len))
+    abort();
+}
+
+
+/**
+ * Main function for the thread that runs the interaction with
+ * the upgraded socket.
+ *
+ * @param cls the handle for the upgrade
+ */
+static void *
+run_usock (void *cls)
+{
+  struct MHD_UpgradeResponseHandle *urh = cls;
+
+  send_all (usock,
+            "Hello");
+  recv_all (usock,
+            "World");
+  send_all (usock,
+            "Finished");
+  MHD_upgrade_action (urh,
+                      MHD_UPGRADE_ACTION_CLOSE);
+  return NULL;
+}
 
 
 /**
+ * Main function for the thread that runs the client-side of the
+ * interaction with the upgraded socket.
+ *
+ * @param cls the client socket
+ */
+static void *
+run_usock_client (void *cls)
+{
+  wr_socket *sock = cls;
+
+  send_all (*sock,
+            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
+  recv_hdr (*sock);
+  recv_all (*sock,
+            "Hello");
+  send_all (*sock,
+            "World");
+  recv_all (*sock,
+            "Finished");
+  wr_close (*sock);
+  done = 1;
+  return NULL;
+}
+
+
+/**
+ * Function called after a protocol "upgrade" response was sent
+ * successfully and the socket should now be controlled by some
+ * protocol other than HTTP.
+ *
+ * Any data already received on the socket will be made available in
+ * @e extra_in.  This can happen if the application sent extra data
+ * before MHD send the upgrade response.  The application should
+ * treat data from @a extra_in as if it had read it from the socket.
+ *
+ * Note that the application must not close() @a sock directly,
+ * but instead use #MHD_upgrade_action() for special operations
+ * on @a sock.
+ *
+ * Except when in 'thread-per-connection' mode, implementations
+ * of this function should never block (as it will still be called
+ * from within the main event loop).
+ *
+ * @param cls closure, whatever was given to 
#MHD_create_response_for_upgrade().
+ * @param connection original HTTP connection handle,
+ *                   giving the function a last chance
+ *                   to inspect the original HTTP request
+ * @param con_cls last value left in `con_cls` of the 
`MHD_AccessHandlerCallback`
+ * @param extra_in if we happened to have read bytes after the
+ *                 HTTP header already (because the client sent
+ *                 more than the HTTP header of the request before
+ *                 we sent the upgrade response),
+ *                 these are the extra bytes already read from @a sock
+ *                 by MHD.  The application should treat these as if
+ *                 it had read them from @a sock.
+ * @param extra_in_size number of bytes in @a extra_in
+ * @param sock socket to use for bi-directional communication
+ *        with the client.  For HTTPS, this may not be a socket
+ *        that is directly connected to the client and thus certain
+ *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
+ *        may not work as expected (as the socket could be from a
+ *        socketpair() or a TCP-loopback).  The application is expected
+ *        to perform read()/recv() and write()/send() calls on the socket.
+ *        The application may also call shutdown(), but must not call
+ *        close() directly.
+ * @param urh argument for #MHD_upgrade_action()s on this @a connection.
+ *        Applications must eventually use this callback to (indirectly)
+ *        perform the close() action on the @a sock.
+ */
+static void
+upgrade_cb (void *cls,
+            struct MHD_Connection *connection,
+            void *con_cls,
+            const char *extra_in,
+            size_t extra_in_size,
+            MHD_socket sock,
+            struct MHD_UpgradeResponseHandle *urh)
+{
+  usock = wr_create_from_plain_sckt (sock);
+  if (0 != extra_in_size)
+    abort ();
+  if (0 != pthread_create (&pt,
+                           NULL,
+                           &run_usock,
+                           urh))
+    abort ();
+}
+
+
+/**
+ * A client has requested the given url using the given method
+ * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
+ * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
+ * must call MHD callbacks to provide content to give back to the
+ * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
+ * #MHD_HTTP_NOT_FOUND, etc.).
+ *
+ * @param cls argument given together with the function
+ *        pointer when the handler was registered with MHD
+ * @param url the requested url
+ * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
+ *        #MHD_HTTP_METHOD_PUT, etc.)
+ * @param version the HTTP version string (i.e.
+ *        #MHD_HTTP_VERSION_1_1)
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ *        for a POST that fits into memory and that is encoded
+ *        with a supported encoding, the POST data will NOT be
+ *        given in upload_data and is instead available as
+ *        part of #MHD_get_connection_values; very large POST
+ *        data *will* be made available incrementally in
+ *        @a upload_data)
+ * @param upload_data_size set initially to the size of the
+ *        @a upload_data provided; the method must update this
+ *        value to the number of bytes NOT processed;
+ * @param con_cls pointer that the callback can set to some
+ *        address and that will be preserved by MHD for future
+ *        calls for this request; since the access handler may
+ *        be called many times (i.e., for a PUT/POST operation
+ *        with plenty of upload data) this allows the application
+ *        to easily associate some request-specific state.
+ *        If necessary, this state can be cleaned up in the
+ *        global #MHD_RequestCompletedCallback (which
+ *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
+ *        Initially, `*con_cls` will be NULL.
+ * @return #MHD_YES if the connection was handled successfully,
+ *         #MHD_NO if the socket must be closed due to a serios
+ *         error while handling the request
+ */
+static int
+ahc_upgrade (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 **con_cls)
+{
+  struct MHD_Response *resp;
+  int ret;
+
+  if (NULL == *con_cls)
+    abort ();
+  if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ()))
+    abort ();
+  resp = MHD_create_response_for_upgrade (&upgrade_cb,
+                                          NULL);
+  MHD_add_response_header (resp,
+                           MHD_HTTP_HEADER_UPGRADE,
+                           "Hello World Protocol");
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_SWITCHING_PROTOCOLS,
+                            resp);
+  MHD_destroy_response (resp);
+  return ret;
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ */
+static void
+run_mhd_select_loop (struct MHD_Daemon *daemon)
+{
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  MHD_socket max_fd;
+  MHD_UNSIGNED_LONG_LONG to;
+  struct timeval tv;
+
+  while (! done)
+    {
+      FD_ZERO (&rs);
+      FD_ZERO (&ws);
+      FD_ZERO (&es);
+      max_fd = -1;
+      to = 1000;
+
+      if (MHD_YES !=
+          MHD_get_fdset (daemon,
+                         &rs,
+                         &ws,
+                         &es,
+                         &max_fd))
+        abort ();
+      (void) MHD_get_timeout (daemon,
+                              &to);
+      if (1000 < to)
+        to = 1000;
+      tv.tv_sec = to / 1000;
+      tv.tv_usec = 1000 * (to % 1000);
+      if (0 > MHD_SYS_select_ (max_fd + 1,
+                               &rs,
+                               &ws,
+                               &es,
+                               &tv))
+        abort ();
+      MHD_run_from_select (daemon,
+                           &rs,
+                           &ws,
+                           &es);
+    }
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ */
+static void
+run_mhd_poll_loop (struct MHD_Daemon *daemon)
+{
+  abort (); /* currently not implementable with existing MHD API */
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ */
+static void
+run_mhd_epoll_loop (struct MHD_Daemon *daemon)
+{
+  const union MHD_DaemonInfo *di;
+  MHD_socket ep;
+  fd_set rs;
+  MHD_UNSIGNED_LONG_LONG to;
+  struct timeval tv;
+
+  di = MHD_get_daemon_info (daemon,
+                            MHD_DAEMON_INFO_EPOLL_FD);
+  ep = di->listen_fd;
+  while (! done)
+    {
+      FD_ZERO (&rs);
+      to = 1000;
+
+      FD_SET (ep, &rs);
+      (void) MHD_get_timeout (daemon,
+                              &to);
+      if (1000 < to)
+        to = 1000;
+      tv.tv_sec = to / 1000;
+      tv.tv_usec = 1000 * (to % 1000);
+      select (ep + 1,
+              &rs,
+              NULL,
+              NULL,
+              &tv);
+      MHD_run (daemon);
+    }
+}
+
+
+/**
+ * Run the MHD external event loop using select.
+ *
+ * @param daemon daemon to run it for
+ */
+static void
+run_mhd_loop (struct MHD_Daemon *daemon,
+              int flags)
+{
+  if (0 != (flags & MHD_USE_POLL))
+    run_mhd_poll_loop (daemon);
+#if EPOLL_SUPPORT
+  else if (0 != (flags & MHD_USE_EPOLL))
+    run_mhd_epoll_loop (daemon);
+#endif
+  else
+    run_mhd_select_loop (daemon);
+}
+
+static bool test_tls;
+
+/**
  * Test upgrading a connection.
  *
  * @param flags which event loop style should be tested
@@ -55,13 +994,17 @@ static int
 test_upgrade (int flags,
               unsigned int pool)
 {
-  struct MHD_Daemon *d;
-  MHD_socket sock;
+  struct MHD_Daemon *d = NULL;
+  wr_socket sock;
   struct sockaddr_in sa;
+#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
+  pid_t pid = -1;
+#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
 
   done = 0;
 
-  d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_UPGRADE,
+  if (!test_tls)
+    d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_UPGRADE,
                         1080,
                         NULL, NULL,
                         &ahc_upgrade, NULL,
@@ -70,18 +1013,52 @@ test_upgrade (int flags,
                         MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, 
NULL,
                         MHD_OPTION_THREAD_POOL_SIZE, pool,
                         MHD_OPTION_END);
+#ifdef HTTPS_SUPPORT
+  else
+    d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_UPGRADE | 
MHD_USE_TLS,
+                          1080,
+                          NULL, NULL,
+                          &ahc_upgrade, NULL,
+                          MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
+                          MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, 
NULL,
+                          MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, 
NULL,
+                          MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
+                          MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
+                          MHD_OPTION_THREAD_POOL_SIZE, pool,
+                          MHD_OPTION_END);
+#endif /* HTTPS_SUPPORT */
   if (NULL == d)
     return 2;
-  sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
-  if (MHD_INVALID_SOCKET == sock)
-    abort ();
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (1080);
-  sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-  if (0 != connect (sock,
-                    (struct sockaddr *) &sa,
-                    sizeof (sa)))
-    abort ();
+  if (!test_tls || TLS_LIB_GNUTLS == use_tls_tool)
+    {
+      sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt ();
+      if (WR_BAD == sock)
+        abort ();
+      sa.sin_family = AF_INET;
+      sa.sin_port = htons (1080);
+      sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+      if (0 != wr_connect (sock,
+                        (struct sockaddr *) &sa,
+                        sizeof (sa)))
+        abort ();
+    }
+  else
+    {
+#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
+      MHD_socket tls_fork_sock;
+      if (-1 == (pid = gnutlscli_connect (&tls_fork_sock, 1080)))
+        {
+          MHD_stop_daemon (d);
+          return 4;
+        }
+      sock =  wr_create_from_plain_sckt (tls_fork_sock);
+      if (WR_BAD == sock)
+        abort ();
+#else  /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
+      abort ();
+#endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
+    }
+
   if (0 != pthread_create (&pt_client,
                            NULL,
                            &run_usock_client,
@@ -94,6 +1071,10 @@ test_upgrade (int flags,
                 NULL);
   pthread_join (pt,
                 NULL);
+#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
+  if (test_tls && TLS_LIB_GNUTLS != use_tls_tool)
+    waitpid (pid, NULL, 0);
+#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
   MHD_stop_daemon (d);
   return 0;
 }
@@ -106,9 +1087,58 @@ main (int argc,
   int error_count = 0;
   int res;
 
+  use_tls_tool = TLS_CLI_NO_TOOL;
+  test_tls = has_in_name(argv[0], "_tls");
+
   if (has_param(argc, argv, "-v") || has_param(argc, argv, "--verbose"))
     verbose = 1;
 
+  if (test_tls)
+    {
+#ifdef HTTPS_SUPPORT
+      if (has_param(argc, argv, "--use-gnutls-cli"))
+        use_tls_tool = TLS_CLI_GNUTLS;
+      else if (has_param(argc, argv, "--use-openssl"))
+        use_tls_tool = TLS_CLI_OPENSSL;
+      else if (has_param(argc, argv, "--use-gnutls-lib"))
+        use_tls_tool = TLS_LIB_GNUTLS;
+#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
+      else if (0 == system ("gnutls-cli --version 1> /dev/null"))
+        use_tls_tool = TLS_CLI_GNUTLS;
+      else if (0 == system ("openssl version 1> /dev/null"))
+        use_tls_tool = TLS_CLI_OPENSSL;
+#endif /* HAVE_FORK && HAVE_WAITPID */
+      else
+        use_tls_tool = TLS_LIB_GNUTLS; /* Should be available as MHD use it. */
+      if (verbose)
+        {
+          switch (use_tls_tool)
+          {
+            case TLS_CLI_GNUTLS:
+              printf ("GnuTLS-CLI will be used for testing.\n");
+              break;
+            case TLS_CLI_OPENSSL:
+              printf ("Command line version of OpenSSL will be used for 
testing.\n");
+              break;
+            case TLS_LIB_GNUTLS:
+              printf ("GnuTLS library will be used for testing.\n");
+              break;
+            default:
+              abort ();
+          }
+        }
+      if (TLS_LIB_GNUTLS == use_tls_tool && GNUTLS_E_SUCCESS != 
gnutls_global_init())
+        abort ();
+
+#else  /* ! HTTPS_SUPPORT */
+      fprintf (stderr, "HTTPS support was disabled by configure.\n");
+      return 99;
+#endif /* ! HTTPS_SUPPORT */
+    }
+
+  /* run tests */
+  if (verbose)
+    printf ("Starting HTTP \"Upgrade\" tests with %s connections.\n", test_tls 
? "TLS" : "plain");
   /* try external select */
   res = test_upgrade (0,
                       0);
@@ -194,5 +1224,9 @@ main (int argc,
     fprintf (stderr,
              "Error (code: %u)\n",
              error_count);
+#ifdef HTTPS_SUPPORT
+  if (test_tls && TLS_LIB_GNUTLS == use_tls_tool)
+    gnutls_global_deinit();
+#endif /* HTTPS_SUPPORT */
   return error_count != 0;       /* 0 == pass */
 }
diff --git a/src/microhttpd/test_upgrade_common.c 
b/src/microhttpd/test_upgrade_common.c
deleted file mode 100644
index a96ffcd..0000000
--- a/src/microhttpd/test_upgrade_common.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2016 Christian Grothoff
-
-     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 2, or (at your
-     option) any later version.
-
-     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.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_upgrade_common.c
- * @brief Shared logic for testcases for libmicrohttpd upgrading a connection
- * @author Christian Grothoff
- */
-
-#include "mhd_sockets.h"
-
-/**
- * Thread we use to run the interaction with the upgraded socket.
- */
-static pthread_t pt;
-
-/**
- * Will be set to the upgraded socket.
- */
-static MHD_socket usock;
-
-/**
- * Thread we use to run the interaction with the upgraded socket.
- */
-static pthread_t pt_client;
-
-/**
- * Flag set to 1 once the test is finished.
- */
-static int done;
-
-
-static void
-notify_completed_cb (void *cls,
-                     struct MHD_Connection *connection,
-                     void **con_cls,
-                     enum MHD_RequestTerminationCode toe)
-{
-  if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) &&
-       (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) &&
-       (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) )
-    abort ();
-  if (((long) *con_cls) != (long) pthread_self ())
-    abort ();
-  *con_cls = NULL;
-}
-
-
-/**
- * Logging callback.
- *
- * @param cls logging closure (NULL)
- * @param uri access URI
- * @param connection connection handle
- * @return #TEST_PTR
- */
-static void *
-log_cb (void *cls,
-        const char *uri,
-        struct MHD_Connection *connection)
-{
-  if (0 != strcmp (uri,
-                   "/"))
-    abort ();
-  return (void *) (long) pthread_self ();
-}
-
-
-/**
- * Function to check that MHD properly notifies about starting
- * and stopping.
- *
- * @param cls client-defined closure
- * @param connection connection handle
- * @param socket_context socket-specific pointer where the
- *                       client can associate some state specific
- *                       to the TCP connection; note that this is
- *                       different from the "con_cls" which is per
- *                       HTTP request.  The client can initialize
- *                       during #MHD_CONNECTION_NOTIFY_STARTED and
- *                       cleanup during #MHD_CONNECTION_NOTIFY_CLOSED
- *                       and access in the meantime using
- *                       #MHD_CONNECTION_INFO_SOCKET_CONTEXT.
- * @param toe reason for connection notification
- * @see #MHD_OPTION_NOTIFY_CONNECTION
- * @ingroup request
- */
-static void
-notify_connection_cb (void *cls,
-                      struct MHD_Connection *connection,
-                      void **socket_context,
-                      enum MHD_ConnectionNotificationCode toe)
-{
-  static int started;
-
-  switch (toe)
-  {
-  case MHD_CONNECTION_NOTIFY_STARTED:
-    if (MHD_NO != started)
-      abort ();
-    started = MHD_YES;
-    *socket_context = &started;
-    break;
-  case MHD_CONNECTION_NOTIFY_CLOSED:
-    if (MHD_YES != started)
-      abort ();
-    if (&started != *socket_context)
-      abort ();
-    *socket_context = NULL;
-    started = MHD_NO;
-    break;
-  }
-}
-
-
-/**
- * Change socket to blocking.
- *
- * @param fd the socket to manipulate
- * @return non-zero if succeeded, zero otherwise
- */
-static void
-make_blocking (MHD_socket fd)
-{
-#if defined(MHD_POSIX_SOCKETS)
-  int flags;
-
-  flags = fcntl (fd, F_GETFL);
-  if (-1 == flags)
-    return;
-  if ((flags & ~O_NONBLOCK) != flags)
-    if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
-      abort ();
-#elif defined(MHD_WINSOCK_SOCKETS)
-  unsigned long flags = 1;
-
-  ioctlsocket (fd, FIONBIO, &flags);
-#endif /* MHD_WINSOCK_SOCKETS */
-
-}
-
-
-static void
-send_all (MHD_socket sock,
-          const char *text)
-{
-  size_t len = strlen (text);
-  ssize_t ret;
-
-  make_blocking (sock);
-  for (size_t off = 0; off < len; off += ret)
-    {
-      ret = MHD_send_ (sock,
-                       &text[off],
-                       len - off);
-      if (0 > ret)
-        {
-          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-    }
-}
-
-
-/**
- * Read character-by-character until we
- * get '\r\n\r\n'.
- */
-static void
-recv_hdr (MHD_socket sock)
-{
-  unsigned int i;
-  char next;
-  char c;
-  ssize_t ret;
-
-  make_blocking (sock);
-  next = '\r';
-  i = 0;
-  while (i < 4)
-    {
-      ret = MHD_recv_ (sock,
-                       &c,
-                       1);
-      if (0 > ret)
-        {
-          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
-            continue;
-          abort ();
-        }
-      if (0 == ret)
-        continue;
-      if (c == next)
-        {
-          i++;
-          if (next == '\r')
-            next = '\n';
-          else
-            next = '\r';
-          continue;
-        }
-      if (c == '\r')
-        {
-          i = 1;
-          next = '\n';
-          continue;
-        }
-      i = 0;
-      next = '\r';
-    }
-}
-
-
-static void
-recv_all (MHD_socket sock,
-          const char *text)
-{
-  size_t len = strlen (text);
-  char buf[len];
-  ssize_t ret;
-
-  make_blocking (sock);
-  for (size_t off = 0; off < len; off += ret)
-    {
-      ret = MHD_recv_ (sock,
-                       &buf[off],
-                       len - off);
-      if (0 > ret)
-        {
-          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
-            {
-              ret = 0;
-              continue;
-            }
-          abort ();
-        }
-    }
-  if (0 != strncmp (text, buf, len))
-    abort();
-}
-
-
-/**
- * Main function for the thread that runs the interaction with
- * the upgraded socket.
- *
- * @param cls the handle for the upgrade
- */
-static void *
-run_usock (void *cls)
-{
-  struct MHD_UpgradeResponseHandle *urh = cls;
-
-  send_all (usock,
-            "Hello");
-  recv_all (usock,
-            "World");
-  send_all (usock,
-            "Finished");
-  MHD_upgrade_action (urh,
-                      MHD_UPGRADE_ACTION_CLOSE);
-  return NULL;
-}
-
-
-/**
- * Main function for the thread that runs the client-side of the
- * interaction with the upgraded socket.
- *
- * @param cls the client socket
- */
-static void *
-run_usock_client (void *cls)
-{
-  MHD_socket *sock = cls;
-
-  send_all (*sock,
-            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
-  recv_hdr (*sock);
-  recv_all (*sock,
-            "Hello");
-  send_all (*sock,
-            "World");
-  recv_all (*sock,
-            "Finished");
-  MHD_socket_close_chk_ (*sock);
-  done = 1;
-  return NULL;
-}
-
-
-/**
- * Function called after a protocol "upgrade" response was sent
- * successfully and the socket should now be controlled by some
- * protocol other than HTTP.
- *
- * Any data already received on the socket will be made available in
- * @e extra_in.  This can happen if the application sent extra data
- * before MHD send the upgrade response.  The application should
- * treat data from @a extra_in as if it had read it from the socket.
- *
- * Note that the application must not close() @a sock directly,
- * but instead use #MHD_upgrade_action() for special operations
- * on @a sock.
- *
- * Except when in 'thread-per-connection' mode, implementations
- * of this function should never block (as it will still be called
- * from within the main event loop).
- *
- * @param cls closure, whatever was given to 
#MHD_create_response_for_upgrade().
- * @param connection original HTTP connection handle,
- *                   giving the function a last chance
- *                   to inspect the original HTTP request
- * @param con_cls last value left in `con_cls` of the 
`MHD_AccessHandlerCallback`
- * @param extra_in if we happened to have read bytes after the
- *                 HTTP header already (because the client sent
- *                 more than the HTTP header of the request before
- *                 we sent the upgrade response),
- *                 these are the extra bytes already read from @a sock
- *                 by MHD.  The application should treat these as if
- *                 it had read them from @a sock.
- * @param extra_in_size number of bytes in @a extra_in
- * @param sock socket to use for bi-directional communication
- *        with the client.  For HTTPS, this may not be a socket
- *        that is directly connected to the client and thus certain
- *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
- *        may not work as expected (as the socket could be from a
- *        socketpair() or a TCP-loopback).  The application is expected
- *        to perform read()/recv() and write()/send() calls on the socket.
- *        The application may also call shutdown(), but must not call
- *        close() directly.
- * @param urh argument for #MHD_upgrade_action()s on this @a connection.
- *        Applications must eventually use this callback to (indirectly)
- *        perform the close() action on the @a sock.
- */
-static void
-upgrade_cb (void *cls,
-            struct MHD_Connection *connection,
-            void *con_cls,
-            const char *extra_in,
-            size_t extra_in_size,
-            MHD_socket sock,
-            struct MHD_UpgradeResponseHandle *urh)
-{
-  usock = sock;
-  if (0 != extra_in_size)
-    abort ();
-  if (0 != pthread_create (&pt,
-                           NULL,
-                           &run_usock,
-                           urh))
-    abort ();
-}
-
-
-/**
- * A client has requested the given url using the given method
- * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
- * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
- * must call MHD callbacks to provide content to give back to the
- * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
- * #MHD_HTTP_NOT_FOUND, etc.).
- *
- * @param cls argument given together with the function
- *        pointer when the handler was registered with MHD
- * @param url the requested url
- * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
- *        #MHD_HTTP_METHOD_PUT, etc.)
- * @param version the HTTP version string (i.e.
- *        #MHD_HTTP_VERSION_1_1)
- * @param upload_data the data being uploaded (excluding HEADERS,
- *        for a POST that fits into memory and that is encoded
- *        with a supported encoding, the POST data will NOT be
- *        given in upload_data and is instead available as
- *        part of #MHD_get_connection_values; very large POST
- *        data *will* be made available incrementally in
- *        @a upload_data)
- * @param upload_data_size set initially to the size of the
- *        @a upload_data provided; the method must update this
- *        value to the number of bytes NOT processed;
- * @param con_cls pointer that the callback can set to some
- *        address and that will be preserved by MHD for future
- *        calls for this request; since the access handler may
- *        be called many times (i.e., for a PUT/POST operation
- *        with plenty of upload data) this allows the application
- *        to easily associate some request-specific state.
- *        If necessary, this state can be cleaned up in the
- *        global #MHD_RequestCompletedCallback (which
- *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
- *        Initially, `*con_cls` will be NULL.
- * @return #MHD_YES if the connection was handled successfully,
- *         #MHD_NO if the socket must be closed due to a serios
- *         error while handling the request
- */
-static int
-ahc_upgrade (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 **con_cls)
-{
-  struct MHD_Response *resp;
-  int ret;
-
-  if (((long) *con_cls) != (long) pthread_self ())
-    abort ();
-  resp = MHD_create_response_for_upgrade (&upgrade_cb,
-                                          NULL);
-  MHD_add_response_header (resp,
-                           MHD_HTTP_HEADER_UPGRADE,
-                           "Hello World Protocol");
-  ret = MHD_queue_response (connection,
-                            MHD_HTTP_SWITCHING_PROTOCOLS,
-                            resp);
-  MHD_destroy_response (resp);
-  return ret;
-}
-
-
-/**
- * Run the MHD external event loop using select.
- *
- * @param daemon daemon to run it for
- */
-static void
-run_mhd_select_loop (struct MHD_Daemon *daemon)
-{
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  MHD_socket max_fd;
-  MHD_UNSIGNED_LONG_LONG to;
-  struct timeval tv;
-
-  while (! done)
-    {
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      max_fd = -1;
-      to = 1000;
-
-      if (MHD_YES !=
-          MHD_get_fdset (daemon,
-                         &rs,
-                         &ws,
-                         &es,
-                         &max_fd))
-        abort ();
-      (void) MHD_get_timeout (daemon,
-                              &to);
-      if (1000 < to)
-        to = 1000;
-      tv.tv_sec = to / 1000;
-      tv.tv_usec = 1000 * (to % 1000);
-      if (0 > MHD_SYS_select_ (max_fd + 1,
-                               &rs,
-                               &ws,
-                               &es,
-                               &tv))
-        abort ();
-      MHD_run_from_select (daemon,
-                           &rs,
-                           &ws,
-                           &es);
-    }
-}
-
-
-/**
- * Run the MHD external event loop using select.
- *
- * @param daemon daemon to run it for
- */
-static void
-run_mhd_poll_loop (struct MHD_Daemon *daemon)
-{
-  abort (); /* currently not implementable with existing MHD API */
-}
-
-
-/**
- * Run the MHD external event loop using select.
- *
- * @param daemon daemon to run it for
- */
-static void
-run_mhd_epoll_loop (struct MHD_Daemon *daemon)
-{
-  const union MHD_DaemonInfo *di;
-  MHD_socket ep;
-  fd_set rs;
-  MHD_UNSIGNED_LONG_LONG to;
-  struct timeval tv;
-
-  di = MHD_get_daemon_info (daemon,
-                            MHD_DAEMON_INFO_EPOLL_FD);
-  ep = di->listen_fd;
-  while (! done)
-    {
-      FD_ZERO (&rs);
-      to = 1000;
-
-      FD_SET (ep, &rs);
-      (void) MHD_get_timeout (daemon,
-                              &to);
-      if (1000 < to)
-        to = 1000;
-      tv.tv_sec = to / 1000;
-      tv.tv_usec = 1000 * (to % 1000);
-      select (ep + 1,
-              &rs,
-              NULL,
-              NULL,
-              &tv);
-      MHD_run (daemon);
-    }
-}
-
-
-/**
- * Run the MHD external event loop using select.
- *
- * @param daemon daemon to run it for
- */
-static void
-run_mhd_loop (struct MHD_Daemon *daemon,
-              int flags)
-{
-  if (0 != (flags & MHD_USE_POLL))
-    run_mhd_poll_loop (daemon);
-#if EPOLL_SUPPORT
-  else if (0 != (flags & MHD_USE_EPOLL))
-    run_mhd_epoll_loop (daemon);
-#endif
-  else
-    run_mhd_select_loop (daemon);
-}
diff --git a/src/microhttpd/test_upgrade_ssl.c 
b/src/microhttpd/test_upgrade_ssl.c
deleted file mode 100644
index bb3d2c3..0000000
--- a/src/microhttpd/test_upgrade_ssl.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2016 Christian Grothoff
-
-     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
-     option) any later version.
-
-     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.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_upgrade_ssl.c
- * @brief  Testcase for libmicrohttpd upgrading a connection
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "microhttpd.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-#include <pthread.h>
-#include "mhd_sockets.h"
-#ifdef HAVE_NETINET_IP_H
-#include <netinet/ip.h>
-#endif /* HAVE_NETINET_IP_H */
-#include "mhd_sockets.h"
-#include "test_upgrade_common.c"
-
-#include "../testcurl/https/tls_test_keys.h"
-
-
-enum tls_cli_tool
-{
-  TLS_CLI_NO_TOOL = 0,
-  TLS_CLI_GNUTLS,
-  TLS_CLI_OPENSSL
-};
-
-enum tls_cli_tool use_tool;
-
-/**
- * Fork child that connects via OpenSSL to our @a port.  Allows us to
- * talk to our port over a socket in @a sp without having to worry
- * about TLS.
- *
- * @param location where the socket is returned
- * @return -1 on error, otherwise PID of SSL child process
- */
-static pid_t
-openssl_connect (int *sock,
-                 uint16_t port)
-{
-  pid_t chld;
-  int sp[2];
-  char destination[30];
-
-  if (0 != socketpair (AF_UNIX,
-                       SOCK_STREAM,
-                       0,
-                       sp))
-    return -1;
-  chld = fork ();
-  if (0 != chld)
-    {
-      *sock = sp[1];
-      MHD_socket_close_chk_ (sp[0]);
-      return chld;
-    }
-  MHD_socket_close_chk_ (sp[1]);
-  (void) close (0);
-  (void) close (1);
-  dup2 (sp[0], 0);
-  dup2 (sp[0], 1);
-  MHD_socket_close_chk_ (sp[0]);
-  if (TLS_CLI_GNUTLS == use_tool)
-    {
-      snprintf (destination,
-               sizeof(destination),
-               "%u",
-               (unsigned int) port);
-      execlp ("gnutls-cli",
-             "gnutls-cli",
-             "--insecure",
-             "-p",
-             destination,
-             "localhost",
-             (char *) NULL);
-    }
-  else if (TLS_CLI_OPENSSL == use_tool)
-    {
-      snprintf (destination,
-               sizeof(destination),
-               "localhost:%u",
-               (unsigned int) port);
-      execlp ("openssl",
-             "openssl",
-             "s_client",
-             "-connect",
-             destination,
-             "-verify",
-             "0",
-             (char *) NULL);
-    }
-  _exit (1);
-}
-
-
-/**
- * Test upgrading a connection.
- *
- * @param flags which event loop style should be tested
- * @param pool size of the thread pool, 0 to disable
- */
-static int
-test_upgrade (int flags,
-              unsigned int pool)
-{
-  struct MHD_Daemon *d;
-  MHD_socket sock;
-  pid_t pid;
-
-  done = 0;
-
-  d = MHD_start_daemon (flags | MHD_USE_DEBUG | MHD_USE_UPGRADE | MHD_USE_TLS,
-                        1080,
-                        NULL, NULL,
-                        &ahc_upgrade, NULL,
-                        MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
-                        MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, 
NULL,
-                        MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, 
NULL,
-                        MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
-                        MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
-                        MHD_OPTION_THREAD_POOL_SIZE, pool,
-                        MHD_OPTION_END);
-  if (NULL == d)
-    return 2;
-  if (-1 == (pid = openssl_connect (&sock, 1080)))
-    {
-      MHD_stop_daemon (d);
-      return 4;
-    }
-
-  pthread_create (&pt_client,
-                  NULL,
-                  &run_usock_client,
-                  &sock);
-  if (0 == (flags & (MHD_USE_SELECT_INTERNALLY |
-                     MHD_USE_THREAD_PER_CONNECTION)) )
-    run_mhd_loop (d, flags);
-  pthread_join (pt_client,
-                NULL);
-  if (0 == (flags & (MHD_USE_SELECT_INTERNALLY |
-                     MHD_USE_THREAD_PER_CONNECTION)) )
-    run_mhd_loop (d, flags);
-  pthread_join (pt,
-                NULL);
-  waitpid (pid,
-           NULL,
-           0);
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc,
-      char *const *argv)
-{
-  int error_count = 0;
-
-  use_tool = TLS_CLI_NO_TOOL;
-  if (0 == system ("gnutls-cli --version 1> /dev/null"))
-    use_tool = TLS_CLI_GNUTLS;
-  else if (0 == system ("openssl version 1> /dev/null"))
-    use_tool = TLS_CLI_OPENSSL;
-  else
-    return 77; /* not possible to test */
-
-  /* try external select */
-  error_count += test_upgrade (0,
-                               0);
-#ifdef EPOLL_SUPPORT
-  error_count += test_upgrade (MHD_USE_EPOLL | MHD_USE_TLS,
-                               0);
-#endif
-
-  /* Test thread-per-connection */
-  error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION,
-                               0);
-  error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL,
-                               0);
-
-  /* Test different event loops, with and without thread pool */
-  error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY,
-                               0);
-  error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY,
-                               2);
-#ifdef HAVE_POLL
-  error_count += test_upgrade (MHD_USE_POLL_INTERNALLY,
-                               0);
-  error_count += test_upgrade (MHD_USE_POLL_INTERNALLY,
-                               2);
-#endif
-#ifdef EPOLL_SUPPORT
-  error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY |
-                               MHD_USE_TLS,
-                               0);
-  error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY |
-                               MHD_USE_TLS,
-                               2);
-#endif
-  /* report result */
-  if (0 != error_count)
-    fprintf (stderr,
-             "Error (code: %u)\n",
-             error_count);
-  return error_count != 0;       /* 0 == pass */
-}


hooks/post-receive
-- 
GNU libmicrohttpd



reply via email to

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