diff -u -r -N -p libmicrohttpd-0.9.72-orig/doc/libmicrohttpd.texi libmicrohttpd-0.9.72/doc/libmicrohttpd.texi
--- libmicrohttpd-0.9.72-orig/doc/libmicrohttpd.texi	2020-09-21 12:23:43.000000000 +0000
+++ libmicrohttpd-0.9.72/doc/libmicrohttpd.texi	2021-01-13 21:54:35.159460495 +0000
@@ -1261,6 +1261,11 @@ Handle for a response.
 @end deftp
 
 
+@deftp {C Struct} MHD_Iovec
+An element of an input/output scatter/gather array.
+@end deftp
+
+
 @deftp {C Struct} MHD_PostProcessor
 @cindex POST method
 Handle for @code{POST} processing.
@@ -2143,6 +2148,29 @@ can be released anytime after this call
 @end table
 
 Return @code{NULL} on error (i.e. invalid arguments, out of memory).
+@end deftypefun
+
+
+@deftypefun {struct MHD_Response *} MHD_create_response_from_iovec (const struct MHD_Iovec *iov, int iovcnt, MHD_ContentReaderFreeCallback crfc, void *cls)
+Create a response object from a scatter/gather array.  The response object
+can be extended with header information and then it can be used any number
+of times.
+
+@table @var
+@item iov
+scatter/gather array containing the blocks of data to send on the connection;
+
+@item iovcnt
+number of elements in @var{iov};
+
+@item crfc
+callback to call to free resources associated with @var{iov};
+
+@item cls
+argument to @var{crfc};
+@end table
+
+Return @code{NULL} on error (i.e. invalid arguments, out of memory).
 @end deftypefun
 
 
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/include/microhttpd.h libmicrohttpd-0.9.72/src/include/microhttpd.h
--- libmicrohttpd-0.9.72-orig/src/include/microhttpd.h	2020-12-28 18:41:28.000000000 +0000
+++ libmicrohttpd-0.9.72/src/include/microhttpd.h	2021-01-13 21:54:35.163460664 +0000
@@ -1972,6 +1972,23 @@ union MHD_ConnectionInfo
 
 
 /**
+ * I/O vector type. Provided for use with MHD_create_response_from_iovec.
+ */
+struct MHD_Iovec
+{
+  /**
+   * Base of memory region for I/O.
+   */
+  void *iov_base;
+
+  /**
+   * Length of memory region for I/O.
+   */
+  size_t iov_len;
+};
+
+
+/**
  * Values of this enum are used to specify what
  * information about a connection is desired.
  * @ingroup request
@@ -3228,6 +3245,26 @@ MHD_create_response_from_fd_at_offset64
 
 
 /**
+ * Create a response object from a scatter/gather array.  The response object
+ * can be extended with header information and then be used any number of times.
+ *
+ * @param iov Scatter/gather array for response data -- an internal copy of this
+ *        will be made
+ * @param iovcnt number of elements in iov
+ * @param free_cb callback to clean up any data associated with iov when
+ *        the response is destroyed.
+ * @param cls argument passed to free_cb
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+_MHD_EXTERN struct MHD_Response *
+MHD_create_response_from_iovec (const struct MHD_Iovec *iov,
+                                int iovcnt,
+                                MHD_ContentReaderFreeCallback free_cb,
+                                void *cls);
+
+
+/**
  * Enumeration for actions MHD should perform on the underlying socket
  * of the upgrade.  This API is not finalized, and in particular
  * the final set of actions is yet to be decided. This is just an
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/microhttpd/connection.c libmicrohttpd-0.9.72/src/microhttpd/connection.c
--- libmicrohttpd-0.9.72-orig/src/microhttpd/connection.c	2020-12-28 18:41:28.000000000 +0000
+++ libmicrohttpd-0.9.72/src/microhttpd/connection.c	2021-01-13 21:54:35.167460833 +0000
@@ -2935,7 +2935,8 @@ MHD_connection_handle_write (struct MHD_
                     connection->response_write_position) );
 
       if ( (NULL == resp->crc) &&
-           (0 == connection->response_write_position) )
+           (0 == connection->response_write_position) &&
+           (NULL == resp->data_iov) )
       {
         mhd_assert (resp->total_size >= resp->data_size);
         /* Send response headers alongside the response body, if the body
@@ -2949,6 +2950,17 @@ MHD_connection_handle_write (struct MHD_
                                       resp->data_size,
                                       (resp->total_size == resp->data_size));
       }
+      else if (NULL != resp->data_iov)
+      {
+        ret = MHD_send_hdr_and_body_ (connection,
+                                      &connection->write_buffer
+                                      [connection->write_buffer_send_offset],
+                                      wb_ready,
+                                      false,
+                                      NULL,
+                                      0,
+                                      0);
+      }
       else
       {
         /* This is response for HEAD request or reply body is not allowed
@@ -3018,9 +3030,12 @@ MHD_connection_handle_write (struct MHD_
         ret = MHD_send_sendfile_ (connection);
       }
       else
-#else  /* ! _MHD_HAVE_SENDFILE */
-      if (1)
-#endif /* ! _MHD_HAVE_SENDFILE */
+#endif /* _MHD_HAVE_SENDFILE */
+      if (NULL != response->data_iov)
+      {
+        ret = MHD_send_iovec_ (connection);
+      }
+      else
       {
         data_write_offset = connection->response_write_position
                             - response->data_start;
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/microhttpd/internal.h libmicrohttpd-0.9.72/src/microhttpd/internal.h
--- libmicrohttpd-0.9.72-orig/src/microhttpd/internal.h	2020-12-28 12:17:34.000000000 +0000
+++ libmicrohttpd-0.9.72/src/microhttpd/internal.h	2021-01-13 21:54:35.167460833 +0000
@@ -343,6 +343,21 @@ struct MHD_HTTP_Header
 };
 
 
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+/**
+ * Internally used I/O vector type for use when writev or sendmsg
+ * is available.
+ */
+typedef struct iovec MHD_iovec;
+#else
+/**
+ * Internally used I/O vector type for use when writev or sendmsg
+ * is not availble.
+ */
+typedef struct MHD_Iovec MHD_iovec;
+#endif
+
+
 /**
  * Representation of a response.
  */
@@ -450,6 +465,30 @@ struct MHD_Response
    */
   bool is_pipe;
 
+  /**
+   * I/O vector used with MHD_create_response_from_iovec.
+   */
+  MHD_iovec *data_iov;
+
+  /**
+   * Number of elements in data_iov.
+   */
+  int data_iovcnt;
+
+  /**
+   * Temporary storage for a partially sent I/O vector entry.
+   */
+  MHD_iovec data_iov_tr;
+
+  /**
+   * All remaining elements of the I/O vector not yet sent.
+   */
+  MHD_iovec *data_iov_left;
+
+  /**
+   * Number of elements in data_iov_left.
+   */
+  int data_iovcnt_left;
 };
 
 
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/microhttpd/mhd_send.c libmicrohttpd-0.9.72/src/microhttpd/mhd_send.c
--- libmicrohttpd-0.9.72-orig/src/microhttpd/mhd_send.c	2020-12-28 12:17:34.000000000 +0000
+++ libmicrohttpd-0.9.72/src/microhttpd/mhd_send.c	2021-01-13 21:54:35.171461003 +0000
@@ -1250,3 +1250,144 @@ MHD_send_sendfile_ (struct MHD_Connectio
 
 
 #endif /* _MHD_HAVE_SENDFILE */
+
+
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+
+static ssize_t
+send_iov_nontls (struct MHD_Connection *connection,
+                 MHD_iovec *iovp,
+                 int iovcnt)
+{
+  ssize_t ret;
+  struct iovec *iov = (struct iovec *)iovp;
+#ifdef HAVE_SENDMSG
+  struct msghdr msg;
+#endif
+
+  if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
+       (MHD_CONNECTION_CLOSED == connection->state) )
+  {
+    return MHD_ERR_NOTCONN_;
+  }
+
+#ifdef HAVE_SENDMSG
+  memset(&msg, 0, sizeof(struct msghdr));
+  msg.msg_iov = iov;
+  msg.msg_iovlen = iovcnt;
+  ret = sendmsg (connection->socket_fd, &msg, MSG_NOSIGNAL);
+#else
+  ret = writev (connection->socket_fd, iov, iovcnt);
+#endif
+
+  if (0 > ret)
+  {
+    const int err = MHD_socket_get_error_();
+
+    if (MHD_SCKT_ERR_IS_EAGAIN_(err))
+    {
+#ifdef EPOLL_SUPPORT
+      /* EAGAIN --- no longer write-ready */
+      connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif /* EPOLL_SUPPORT */
+      return MHD_ERR_AGAIN_;
+    }
+    if (MHD_SCKT_ERR_IS_EINTR_ (err))
+      return MHD_ERR_AGAIN_;
+    if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_))
+      return MHD_ERR_CONNRESET_;
+    /* Treat any other error as hard error. */
+    return MHD_ERR_NOTCONN_;
+  }
+#ifdef EPOLL_SUPPORT
+  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif /* EPOLL_SUPPORT */
+  return ret;
+}
+
+#endif /* HAVE_SENDMSG || HAVE_WRITEV */
+
+
+ssize_t
+MHD_send_iovec_ (struct MHD_Connection *connection) {
+  struct MHD_Response *response = connection->response;
+  ssize_t ret, sz;
+  int i;
+  bool do_postsend = false;
+
+#ifdef HTTPS_SUPPORT
+  if (0 != (connection->daemon->options & MHD_USE_TLS))
+  {
+    ret = MHD_send_data_ (connection,
+                          response->data_iov_left[0].iov_base,
+                          response->data_iov_left[0].iov_len,
+                          1 == response->data_iovcnt_left);
+  }
+  else
+#endif /* HTTPS_SUPPORT */
+  {
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+    pre_send_setopt (connection, true, false);
+    do_postsend = true;
+    ret = send_iov_nontls (connection,
+                           response->data_iov_left,
+                           response->data_iovcnt_left);
+#else
+    ret = MHD_send_data_ (connection,
+                          response->data_iov_left[0].iov_base,
+                          response->data_iov_left[0].iov_len,
+                          1 == response->data_iovcnt_left);
+#endif
+  }
+
+  /* Adjust the internal tracking information for the iovec to
+   * take this last send into account. */
+  if (ret >= 0 && ret < response->data_iov_left[0].iov_len)
+  {
+    if (!response->data_iov_tr.iov_base)
+    {
+      response->data_iov_tr = response->data_iov_left[0];
+    }
+
+    response->data_iov_left[0].iov_len -= ret;
+    response->data_iov_left[0].iov_base =
+      ((char *)response->data_iov_left[0].iov_base) + ret;
+  }
+  else if (ret >= 0)
+  {
+    sz = ret - response->data_iov_left[0].iov_len;
+
+    if (response->data_iov_tr.iov_base)
+    {
+      response->data_iov_left[0] = response->data_iov_tr;
+      memset (&response->data_iov_tr, 0, sizeof(MHD_iovec));
+    }
+
+    for (i = 1; i < response->data_iovcnt_left; ++i)
+    {
+      if (sz < response->data_iov_left[i].iov_len)
+      {
+        response->data_iov_tr = response->data_iov_left[0];
+      }
+
+      if (sz <= response->data_iov_left[i].iov_len)
+      {
+        response->data_iov_left[i].iov_len -= sz;
+        response->data_iov_left[i].iov_base =
+          ((char *)response->data_iov_left[i].iov_base) + sz;
+        response->data_iov_left += i;
+        response->data_iovcnt_left -= i;
+        break;
+      }
+
+      sz -= response->data_iov_left[i].iov_len;
+    }
+
+    if (do_postsend && 0 == response->data_iovcnt_left)
+    {
+        post_send_setopt (connection, true, true);
+    }
+  }
+
+  return ret;
+}
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/microhttpd/mhd_send.h libmicrohttpd-0.9.72/src/microhttpd/mhd_send.h
--- libmicrohttpd-0.9.72-orig/src/microhttpd/mhd_send.h	2020-12-26 14:02:37.000000000 +0000
+++ libmicrohttpd-0.9.72/src/microhttpd/mhd_send.h	2021-01-13 21:54:35.171461003 +0000
@@ -111,4 +111,15 @@ MHD_send_sendfile_ (struct MHD_Connectio
 
 #endif
 
+
+/**
+ * Function for sending responses backed by a scatter/gather array.
+ *
+ * @param connection the MHD connection structure
+ * @return actual number of bytes sent
+ */
+ssize_t
+MHD_send_iovec_ (struct MHD_Connection *connection);
+
+
 #endif /* MHD_SEND_H */
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/microhttpd/response.c libmicrohttpd-0.9.72/src/microhttpd/response.c
--- libmicrohttpd-0.9.72-orig/src/microhttpd/response.c	2020-12-28 12:17:34.000000000 +0000
+++ libmicrohttpd-0.9.72/src/microhttpd/response.c	2021-01-13 21:54:35.171461003 +0000
@@ -846,6 +846,76 @@ MHD_create_response_from_buffer_with_fre
 }
 
 
+/**
+ * Create a response object from a scatter/gather array.  The response object
+ * can be extended with header information and then be used any number of times.
+ *
+ * @param iov Scatter/gather array for response data -- an internal copy of this
+ *        will be made
+ * @param iovcnt number of elements in iov
+ * @param free_cb callback to clean up any data associated with iov when
+ *        the response is destroyed.
+ * @param cls argument passed to free_cb
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+_MHD_EXTERN struct MHD_Response *
+MHD_create_response_from_iovec (const struct MHD_Iovec *iov,
+                                int iovcnt,
+                                MHD_ContentReaderFreeCallback free_cb,
+                                void *cls)
+{
+  struct MHD_Response *response;
+  MHD_iovec *tmp;
+  int i;
+  size_t dsz = 0;
+
+  if ((NULL == iov) && (iovcnt > 0))
+    return NULL;
+  if (NULL == (response = MHD_calloc_ (1, sizeof (struct MHD_Response))))
+    return NULL;
+  response->fd = -1;
+#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
+  if (! MHD_mutex_init_ (&response->mutex))
+  {
+    free (response);
+    return NULL;
+  }
+#endif
+  if (NULL == (tmp = malloc(iovcnt * sizeof(MHD_iovec))))
+  {
+#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
+    MHD_mutex_destroy_chk_ (&response->mutex);
+#endif
+    free(response);
+    return NULL;
+  }
+
+  for (i = 0; i < iovcnt; ++i)
+  {
+    tmp[i].iov_base = iov[i].iov_base;
+    tmp[i].iov_len = iov[i].iov_len;
+  }
+
+  response->data_iov = tmp;
+  response->data_iovcnt = iovcnt;
+  response->data_iov_left = tmp;
+  response->data_iovcnt_left = iovcnt;
+  response->crc_cls = cls;
+  response->crfc = free_cb;
+
+  for(i = 0; i < iovcnt; ++i)
+  {
+    dsz += iov[i].iov_len;
+  }
+
+  response->data_size = dsz;
+  response->total_size = dsz;
+  response->reference_count = 1;
+  return response;
+}
+
+
 #ifdef UPGRADE_SUPPORT
 /**
  * This connection-specific callback is provided by MHD to
@@ -1287,6 +1357,12 @@ MHD_destroy_response (struct MHD_Respons
 #endif
   if (NULL != response->crfc)
     response->crfc (response->crc_cls);
+
+  if (NULL != response->data_iov)
+  {
+    free(response->data_iov);
+  }
+
   while (NULL != response->first_header)
   {
     pos = response->first_header;
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/testcurl/Makefile.am libmicrohttpd-0.9.72/src/testcurl/Makefile.am
--- libmicrohttpd-0.9.72-orig/src/testcurl/Makefile.am	2020-10-31 16:01:04.000000000 +0000
+++ libmicrohttpd-0.9.72/src/testcurl/Makefile.am	2021-01-13 21:54:35.171461003 +0000
@@ -50,10 +50,11 @@ if HAVE_POSIX_THREADS
 THREAD_ONLY_TESTS += \
   perf_get_concurrent
 endif
-  
+
 if HAVE_CURL
 check_PROGRAMS = \
   test_get \
+  test_get_iovec \
   test_get_sendfile \
   test_delete \
   test_patch \
@@ -65,6 +66,7 @@ check_PROGRAMS = \
   test_parse_cookies \
   test_large_put \
   test_get11 \
+  test_get_iovec11 \
   test_get_sendfile11 \
   test_patch11 \
   test_put11 \
@@ -187,6 +189,12 @@ test_digestauth_with_arguments_LDADD = \
   $(top_builddir)/src/microhttpd/libmicrohttpd.la \
   @LIBGCRYPT_LIBS@ @LIBCURL@
 
+test_get_iovec_SOURCES = \
+  test_get_iovec.c mhd_has_in_name.h
+test_get_iovec_LDADD = \
+  $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+  @LIBCURL@
+
 test_get_sendfile_SOURCES = \
   test_get_sendfile.c mhd_has_in_name.h
 test_get_sendfile_LDADD = \
@@ -275,7 +283,7 @@ test_put_chunked_SOURCES = \
 test_put_chunked_LDADD = \
   $(top_builddir)/src/microhttpd/libmicrohttpd.la \
   @LIBCURL@
-  
+
 test_add_conn_SOURCES = \
   test_add_conn.c $(top_srcdir)/src/microhttpd/test_helpers.h
 test_add_conn_CFLAGS = \
@@ -314,6 +322,12 @@ test_get11_LDADD = \
   $(top_builddir)/src/microhttpd/libmicrohttpd.la \
   @LIBCURL@
 
+test_get_iovec11_SOURCES = \
+  test_get_iovec.c mhd_has_in_name.h
+test_get_iovec11_LDADD = \
+  $(top_builddir)/src/microhttpd/libmicrohttpd.la \
+  @LIBCURL@
+
 test_get_sendfile11_SOURCES = \
   test_get_sendfile.c mhd_has_in_name.h
 test_get_sendfile11_LDADD = \
diff -u -r -N -p libmicrohttpd-0.9.72-orig/src/testcurl/test_get_iovec.c libmicrohttpd-0.9.72/src/testcurl/test_get_iovec.c
--- libmicrohttpd-0.9.72-orig/src/testcurl/test_get_iovec.c	1970-01-01 00:00:00.000000000 +0000
+++ libmicrohttpd-0.9.72/src/testcurl/test_get_iovec.c	2021-01-13 21:54:35.171461003 +0000
@@ -0,0 +1,658 @@
+/*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2009 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_get_iovec.c
+ * @brief  Testcase for libmicrohttpd response from scatter/gather array
+ * @author Christian Grothoff
+ * @author Lawrence Sebald
+ */
+
+/*
+ * This test is largely derived from the test_get_sendfile.c file, with the
+ * daemon using MHD_create_response_from_iovec instead of working from an fd.
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include "mhd_sockets.h"
+#include "mhd_has_in_name.h"
+
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+
+#if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
+#undef MHD_CPU_COUNT
+#endif
+#if ! defined(MHD_CPU_COUNT)
+#define MHD_CPU_COUNT 2
+#endif
+
+#define TESTSTR_SIZE   (10 * 1024)
+#define TESTSTR_IOVCNT 10
+
+static int oneone;
+
+static int readbuf[TESTSTR_SIZE * 2 / sizeof(int)];
+
+struct CBC
+{
+  int *buf;
+  size_t pos;
+  size_t size;
+};
+
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+  struct CBC *cbc = ctx;
+
+  if (cbc->pos + size * nmemb > cbc->size)
+    return 0;                   /* overflow */
+  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+  cbc->pos += size * nmemb;
+  return size * nmemb;
+}
+
+
+static void
+iov_free_callback (void *cls)
+{
+  free(cls);
+}
+
+
+static int
+check_read_data (const void *ptr, size_t len)
+{
+  const int *buf;
+  size_t i;
+
+  if (len % sizeof(int))
+    return -1;
+
+  buf = (const int *)ptr;
+
+  for (i = 0; i < len / sizeof(int); ++i)
+  {
+    if (buf[i] != i)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+static enum MHD_Result
+ahc_echo (void *cls,
+          struct MHD_Connection *connection,
+          const char *url,
+          const char *method,
+          const char *version,
+          const char *upload_data, size_t *upload_data_size,
+          void **unused)
+{
+  static int ptr;
+  const char *me = cls;
+  struct MHD_Response *response;
+  enum MHD_Result ret;
+  int *data;
+  struct MHD_Iovec iov[TESTSTR_IOVCNT];
+  int i;
+  (void) url; (void) version;                      /* Unused. Silent compiler warning. */
+  (void) upload_data; (void) upload_data_size;     /* Unused. Silent compiler warning. */
+
+  if (0 != strcmp (me, method))
+    return MHD_NO;              /* unexpected method */
+  if (&ptr != *unused)
+  {
+    *unused = &ptr;
+    return MHD_YES;
+  }
+  *unused = NULL;
+
+  /* Create some test data. */
+  if (NULL == (data = malloc(TESTSTR_SIZE)))
+    return MHD_NO;
+
+  for (i = 0; i < TESTSTR_SIZE / sizeof(int); ++i)
+  {
+    data[i] = i;
+  }
+
+  for (i = 0; i < TESTSTR_IOVCNT; ++i)
+  {
+    iov[i].iov_base = data + (i * (TESTSTR_SIZE / TESTSTR_IOVCNT / sizeof(int)));
+    iov[i].iov_len = TESTSTR_SIZE / TESTSTR_IOVCNT;
+  }
+
+  response = MHD_create_response_from_iovec (iov,
+                                             TESTSTR_IOVCNT,
+                                             &iov_free_callback,
+                                             data);
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  MHD_destroy_response (response);
+  if (ret == MHD_NO)
+    abort ();
+  return ret;
+}
+
+
+static int
+testInternalGet ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  struct CBC cbc;
+  CURLcode errornum;
+  int port;
+
+  if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+    port = 0;
+  else
+  {
+    port = 1200;
+    if (oneone)
+      port += 10;
+  }
+
+  cbc.buf = readbuf;
+  cbc.size = TESTSTR_SIZE * 2;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
+                        port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 1;
+  if (0 == port)
+  {
+    const union MHD_DaemonInfo *dinfo;
+    dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
+    if ((NULL == dinfo) || (0 == dinfo->port) )
+    {
+      MHD_stop_daemon (d); return 32;
+    }
+    port = (int) dinfo->port;
+  }
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
+  curl_easy_setopt (c, CURLOPT_PORT, (long) port);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+  if (oneone)
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+  /* NOTE: use of CONNECTTIMEOUT without also
+     setting NOSIGNAL results in really weird
+     crashes on my system!*/
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
+  if (CURLE_OK != (errornum = curl_easy_perform (c)))
+  {
+    fprintf (stderr,
+             "curl_easy_perform failed: `%s'\n",
+             curl_easy_strerror (errornum));
+    curl_easy_cleanup (c);
+    MHD_stop_daemon (d);
+    return 2;
+  }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != TESTSTR_SIZE)
+    return 4;
+  if (0 != check_read_data (cbc.buf, cbc.pos))
+    return 8;
+  return 0;
+}
+
+
+static int
+testMultithreadedGet ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  struct CBC cbc;
+  CURLcode errornum;
+  int port;
+
+  if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+    port = 0;
+  else
+  {
+    port = 1201;
+    if (oneone)
+      port += 10;
+  }
+
+  cbc.buf = readbuf;
+  cbc.size = TESTSTR_SIZE * 2;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
+                        | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
+                        port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  if (0 == port)
+  {
+    const union MHD_DaemonInfo *dinfo;
+    dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
+    if ((NULL == dinfo) || (0 == dinfo->port) )
+    {
+      MHD_stop_daemon (d); return 32;
+    }
+    port = (int) dinfo->port;
+  }
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
+  curl_easy_setopt (c, CURLOPT_PORT, (long) port);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  if (oneone)
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+  /* NOTE: use of CONNECTTIMEOUT without also
+     setting NOSIGNAL results in really weird
+     crashes on my system! */
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
+  if (CURLE_OK != (errornum = curl_easy_perform (c)))
+  {
+    fprintf (stderr,
+             "curl_easy_perform failed: `%s'\n",
+             curl_easy_strerror (errornum));
+    curl_easy_cleanup (c);
+    MHD_stop_daemon (d);
+    return 32;
+  }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != TESTSTR_SIZE)
+    return 64;
+  if (0 != check_read_data (cbc.buf, cbc.pos))
+    return 128;
+  return 0;
+}
+
+
+static int
+testMultithreadedPoolGet ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  struct CBC cbc;
+  CURLcode errornum;
+  int port;
+
+  if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+    port = 0;
+  else
+  {
+    port = 1202;
+    if (oneone)
+      port += 10;
+  }
+
+  cbc.buf = readbuf;
+  cbc.size = TESTSTR_SIZE * 2;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
+                        port, NULL, NULL, &ahc_echo, "GET",
+                        MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT,
+                        MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  if (0 == port)
+  {
+    const union MHD_DaemonInfo *dinfo;
+    dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
+    if ((NULL == dinfo) || (0 == dinfo->port) )
+    {
+      MHD_stop_daemon (d); return 32;
+    }
+    port = (int) dinfo->port;
+  }
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
+  curl_easy_setopt (c, CURLOPT_PORT, (long) port);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  if (oneone)
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+  /* NOTE: use of CONNECTTIMEOUT without also
+     setting NOSIGNAL results in really weird
+     crashes on my system!*/
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
+  if (CURLE_OK != (errornum = curl_easy_perform (c)))
+  {
+    fprintf (stderr,
+             "curl_easy_perform failed: `%s'\n",
+             curl_easy_strerror (errornum));
+    curl_easy_cleanup (c);
+    MHD_stop_daemon (d);
+    return 32;
+  }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != TESTSTR_SIZE)
+    return 64;
+  if (0 != check_read_data (cbc.buf, cbc.pos))
+    return 128;
+  return 0;
+}
+
+
+static int
+testExternalGet ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  struct CBC cbc;
+  CURLM *multi;
+  CURLMcode mret;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  MHD_socket maxsock;
+#ifdef MHD_WINSOCK_SOCKETS
+  int maxposixs; /* Max socket number unused on W32 */
+#else  /* MHD_POSIX_SOCKETS */
+#define maxposixs maxsock
+#endif /* MHD_POSIX_SOCKETS */
+  int running;
+  struct CURLMsg *msg;
+  time_t start;
+  struct timeval tv;
+  int port;
+
+  if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+    port = 0;
+  else
+  {
+    port = 1203;
+    if (oneone)
+      port += 10;
+  }
+
+  multi = NULL;
+  cbc.buf = readbuf;
+  cbc.size = TESTSTR_SIZE * 2;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_ERROR_LOG,
+                        port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 256;
+  if (0 == port)
+  {
+    const union MHD_DaemonInfo *dinfo;
+    dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
+    if ((NULL == dinfo) || (0 == dinfo->port) )
+    {
+      MHD_stop_daemon (d); return 32;
+    }
+    port = (int) dinfo->port;
+  }
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
+  curl_easy_setopt (c, CURLOPT_PORT, (long) port);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
+  if (oneone)
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+  /* NOTE: use of CONNECTTIMEOUT without also
+     setting NOSIGNAL results in really weird
+     crashes on my system! */
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
+
+
+  multi = curl_multi_init ();
+  if (multi == NULL)
+  {
+    curl_easy_cleanup (c);
+    MHD_stop_daemon (d);
+    return 512;
+  }
+  mret = curl_multi_add_handle (multi, c);
+  if (mret != CURLM_OK)
+  {
+    curl_multi_cleanup (multi);
+    curl_easy_cleanup (c);
+    MHD_stop_daemon (d);
+    return 1024;
+  }
+  start = time (NULL);
+  while ((time (NULL) - start < 5) && (multi != NULL))
+  {
+    maxsock = MHD_INVALID_SOCKET;
+    maxposixs = -1;
+    FD_ZERO (&rs);
+    FD_ZERO (&ws);
+    FD_ZERO (&es);
+    curl_multi_perform (multi, &running);
+    mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
+    if (mret != CURLM_OK)
+    {
+      curl_multi_remove_handle (multi, c);
+      curl_multi_cleanup (multi);
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 2048;
+    }
+    if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
+    {
+      curl_multi_remove_handle (multi, c);
+      curl_multi_cleanup (multi);
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 4096;
+    }
+    tv.tv_sec = 0;
+    tv.tv_usec = 1000;
+    if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
+    {
+#ifdef MHD_POSIX_SOCKETS
+      if (EINTR != errno)
+        abort ();
+#else
+      if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 !=
+                                                                      ws.
+                                                                      fd_count)
+          || (0 != es.fd_count) )
+        abort ();
+      Sleep (1000);
+#endif
+    }
+    curl_multi_perform (multi, &running);
+    if (running == 0)
+    {
+      msg = curl_multi_info_read (multi, &running);
+      if (msg == NULL)
+        break;
+      if (msg->msg == CURLMSG_DONE)
+      {
+        if (msg->data.result != CURLE_OK)
+          printf ("%s failed at %s:%d: `%s'\n",
+                  "curl_multi_perform",
+                  __FILE__,
+                  __LINE__, curl_easy_strerror (msg->data.result));
+        curl_multi_remove_handle (multi, c);
+        curl_multi_cleanup (multi);
+        curl_easy_cleanup (c);
+        c = NULL;
+        multi = NULL;
+      }
+    }
+    MHD_run (d);
+  }
+  if (multi != NULL)
+  {
+    curl_multi_remove_handle (multi, c);
+    curl_easy_cleanup (c);
+    curl_multi_cleanup (multi);
+  }
+  MHD_stop_daemon (d);
+  if (cbc.pos != TESTSTR_SIZE)
+    return 8192;
+  if (0 != check_read_data (cbc.buf, cbc.pos))
+    return 16384;
+  return 0;
+}
+
+
+static int
+testUnknownPortGet ()
+{
+  struct MHD_Daemon *d;
+  const union MHD_DaemonInfo *di;
+  CURL *c;
+  struct CBC cbc;
+  CURLcode errornum;
+  int port;
+  char buf[2048];
+
+  struct sockaddr_in addr;
+  socklen_t addr_len = sizeof(addr);
+  memset (&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = 0;
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  cbc.buf = readbuf;
+  cbc.size = TESTSTR_SIZE * 2;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
+                        0, NULL, NULL, &ahc_echo, "GET",
+                        MHD_OPTION_SOCK_ADDR, &addr,
+                        MHD_OPTION_END);
+  if (d == NULL)
+    return 32768;
+
+  if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+  {
+    di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
+    if (di == NULL)
+      return 65536;
+
+    if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len))
+      return 131072;
+
+    if (addr.sin_family != AF_INET)
+      return 26214;
+    port = (int) ntohs (addr.sin_port);
+  }
+  else
+  {
+    const union MHD_DaemonInfo *dinfo;
+    dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
+    if ((NULL == dinfo) || (0 == dinfo->port) )
+    {
+      MHD_stop_daemon (d); return 32;
+    }
+    port = (int) dinfo->port;
+  }
+
+  snprintf (buf, sizeof(buf), "http://127.0.0.1:%d/",
+            port);
+
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, buf);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
+  if (oneone)
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+  /* NOTE: use of CONNECTTIMEOUT without also
+     setting NOSIGNAL results in really weird
+     crashes on my system! */
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
+  if (CURLE_OK != (errornum = curl_easy_perform (c)))
+  {
+    fprintf (stderr,
+             "curl_easy_perform failed: `%s'\n",
+             curl_easy_strerror (errornum));
+    curl_easy_cleanup (c);
+    MHD_stop_daemon (d);
+    return 524288;
+  }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != TESTSTR_SIZE)
+    return 1048576;
+  if (0 != check_read_data (cbc.buf, cbc.pos))
+    return 2097152;
+  return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+  const char *tmp;
+  FILE *f;
+  (void) argc;   /* Unused. Silent compiler warning. */
+
+  if ((NULL == argv) || (0 == argv[0]))
+    return 99;
+  oneone = has_in_name (argv[0], "11");
+
+  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+    return 2;
+  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
+  {
+    errorCount += testInternalGet ();
+    errorCount += testMultithreadedGet ();
+    errorCount += testMultithreadedPoolGet ();
+    errorCount += testUnknownPortGet ();
+  }
+  errorCount += testExternalGet ();
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  curl_global_cleanup ();
+  return errorCount != 0;       /* 0 == pass */
+}
