diff -u -r 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-08 15:29:04.254639951 +0000
@@ -108,6 +108,7 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 #if ! defined(_WIN32) || defined(__CYGWIN__)
 #include <unistd.h>
 #include <sys/time.h>
@@ -2356,6 +2357,23 @@
 
 
 /**
+ * This method is called by libmicrohttpd if we are done with an
+ * iovec-based content reader.  It should  be used to free resources
+ * associated with the content reader.
+ *
+ * @param iov internal copy of I/O vector (will be an exact copy of
+ *            the originally passed I/O vector)
+ * @param iovcnt number of elements in the I/O vector
+ * @param cls extra argument to the callback
+ * @ingroup response
+ */
+typedef void
+(*MHD_IOVContentReaderFreeCallback) (const struct iovec *iov,
+                                     int iovcnt,
+                                     void *cls);
+
+
+/**
  * Iterator over key-value pairs where the value
  * maybe made available in increments and/or may
  * not be zero-terminated.  Used for processing
@@ -3228,6 +3246,26 @@
 
 
 /**
+ * Create a response object from an iovec.  The response object can be
+ * extended with header information and then be used any number of times.
+ *
+ * @param iov I/O vector for response data -- an internal copy of this
+ *        will be made
+ * @param iovcnt number of elements in iov
+ * @param cls extra argument passed to free_cb
+ * @param free_cb callback to clean up any data associated with iov when
+ *        the response is destroyed.
+ * @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 iovec *iov,
+                                int iovcnt,
+                                void *cls,
+                                MHD_IOVContentReaderFreeCallback free_cb);
+
+
+/**
  * 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 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-08 15:29:04.310642072 +0000
@@ -2935,7 +2935,11 @@
                     connection->response_write_position) );
 
       if ( (NULL == resp->crc) &&
-           (0 == connection->response_write_position) )
+           (0 == connection->response_write_position)
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+           && (NULL == resp->data_iov)
+#endif
+         )
       {
         mhd_assert (resp->total_size >= resp->data_size);
         /* Send response headers alongside the response body, if the body
@@ -2949,6 +2953,19 @@
                                       resp->data_size,
                                       (resp->total_size == resp->data_size));
       }
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+      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);
+      }
+#endif
       else
       {
         /* This is response for HEAD request or reply body is not allowed
@@ -3018,9 +3035,16 @@
         ret = MHD_send_sendfile_ (connection);
       }
       else
-#else  /* ! _MHD_HAVE_SENDFILE */
+#endif /* _MHD_HAVE_SENDFILE */
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+      if (NULL != response->data_iov)
+      {
+        ret = MHD_send_iovec_ (connection);
+      }
+      else
+#else /* !(HAVE_SENDMSG || HAVE_WRITEV) */
       if (1)
-#endif /* ! _MHD_HAVE_SENDFILE */
+#endif /* HAVE_SENDMSG || HAVE_WRITEV */
       {
         data_write_offset = connection->response_write_position
                             - response->data_start;
diff -u -r libmicrohttpd-0.9.72-orig/src/microhttpd/daemon.c libmicrohttpd-0.9.72/src/microhttpd/daemon.c
--- libmicrohttpd-0.9.72-orig/src/microhttpd/daemon.c	2020-12-28 12:17:34.000000000 +0000
+++ libmicrohttpd-0.9.72/src/microhttpd/daemon.c	2021-01-08 15:29:04.310642072 +0000
@@ -2356,6 +2356,56 @@
 #endif /* HTTPS_SUPPORT */
 
 
+static int
+internal_queue_connection (struct MHD_Daemon *daemon,
+                           MHD_socket sock,
+                           const struct sockaddr *addr,
+                           socklen_t alen,
+                           bool sk_nonbl)
+{
+  struct MHD_QueuedConn *qc;
+
+  if(!(qc = (struct MHD_QueuedConn *)malloc(sizeof(struct MHD_QueuedConn))))
+    return MHD_NO;
+
+  if(!(qc->addr = (struct sockaddr *)malloc(alen)))
+  {
+    free(qc);
+    return MHD_NO;
+  }
+
+  qc->sock = sock;
+  qc->addr_len = alen;
+  qc->sk_nonbl = sk_nonbl;
+  qc->next = NULL;
+  memcpy(qc->addr, addr, alen);
+
+  MHD_mutex_lock_chk_ (&daemon->qconn_mutex);
+  if(!daemon->qconn_tail)
+  {
+    daemon->qconn_head = qc;
+    daemon->qconn_tail = qc;
+  }
+  else
+  {
+    daemon->qconn_tail->next = qc;
+    daemon->qconn_tail = qc;
+  }
+  MHD_mutex_unlock_chk_(&daemon->qconn_mutex);
+
+  if ( (MHD_ITC_IS_VALID_(daemon->itc)) &&
+       (! MHD_itc_activate_ (daemon->itc, "c")) )
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _("Failed to signal queued connection via inter-thread communication channel."));
+#endif
+  }
+
+  return MHD_YES;
+}
+
+
 /**
  * Do basic preparation work on the new incoming connection.
  *
@@ -3435,6 +3485,16 @@
   }
 #endif /* MHD_USE_POSIX_THREADS || MHD_USE_W32_THREADS */
 
+  if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD) ) &&
+       (0 != (daemon->options & MHD_USE_EPOLL) ) )
+  {
+    return internal_queue_connection (daemon,
+                                      client_socket,
+                                      addr,
+                                      addrlen,
+                                      sk_nonbl);
+  }
+
   return internal_add_connection (daemon,
                                   client_socket,
                                   addr,
@@ -4707,6 +4767,8 @@
   int num_events;
   unsigned int i;
   MHD_socket ls;
+  struct MHD_QueuedConn *qc;
+  struct MHD_QueuedConn *pqc;
 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
   bool run_upgraded = false;
 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
@@ -4992,6 +5054,32 @@
     }
   }
 
+  MHD_mutex_lock_chk_ (&daemon->qconn_mutex);
+  qc = daemon->qconn_head;
+  while(NULL != qc)
+  {
+    if (internal_add_connection(daemon,
+                                qc->sock,
+                                qc->addr,
+                                qc->addr_len,
+                                false,
+                                qc->sk_nonbl,
+                                false) == MHD_NO)
+    {
+#ifdef HAVE_MESSAGES
+      MHD_DLOG (daemon, _("Failed to add queued connection\n"));
+#endif
+      MHD_socket_close_chk_ (qc->sock);
+    }
+
+    free (qc->addr);
+    pqc = qc;
+    qc = qc->next;
+    free (pqc);
+  }
+
+  daemon->qconn_head = daemon->qconn_tail = NULL;
+  MHD_mutex_unlock_chk_ (&daemon->qconn_mutex);
   return MHD_YES;
 }
 
@@ -6009,14 +6097,13 @@
       return MHD_NO;
   }
 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
-  if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
-       (! daemon->was_quiesced) )
+  if (MHD_ITC_IS_VALID_ (daemon->itc))
   {
     event.events = EPOLLIN;
-    event.data.ptr = daemon;
+    event.data.ptr = (void *) epoll_itc_marker;
     if (0 != epoll_ctl (daemon->epoll_fd,
                         EPOLL_CTL_ADD,
-                        ls,
+                        MHD_itc_r_fd_ (daemon->itc),
                         &event))
     {
 #ifdef HAVE_MESSAGES
@@ -6026,16 +6113,16 @@
 #endif
       return MHD_NO;
     }
-    daemon->listen_socket_in_epoll = true;
   }
 
-  if (MHD_ITC_IS_VALID_ (daemon->itc))
+  if ( (MHD_INVALID_SOCKET != (ls = daemon->listen_fd)) &&
+       (! daemon->was_quiesced) )
   {
     event.events = EPOLLIN;
-    event.data.ptr = (void *) epoll_itc_marker;
+    event.data.ptr = daemon;
     if (0 != epoll_ctl (daemon->epoll_fd,
                         EPOLL_CTL_ADD,
-                        MHD_itc_r_fd_ (daemon->itc),
+                        ls,
                         &event))
     {
 #ifdef HAVE_MESSAGES
@@ -6045,7 +6132,9 @@
 #endif
       return MHD_NO;
     }
+    daemon->listen_socket_in_epoll = true;
   }
+
   return MHD_YES;
 }
 
@@ -6230,6 +6319,9 @@
   daemon->sigpipe_blocked = true;
 #endif /* _WIN32 && ! __CYGWIN__ */
 
+  daemon->qconn_head = NULL;
+  daemon->qconn_tail = NULL;
+
   if ( (0 != (*pflags & MHD_USE_THREAD_PER_CONNECTION)) &&
        (0 == (*pflags & MHD_USE_INTERNAL_POLLING_THREAD)) )
   {
@@ -7023,6 +7115,17 @@
   daemon->https_key_password = NULL;
 #endif /* HTTPS_SUPPORT */
 
+#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
+  if (! MHD_mutex_init_ (&daemon->qconn_mutex))
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _("Failed to initialize queued connection mutex\n"));
+#endif
+    goto thread_failed;
+  }
+#endif
+
   return daemon;
 
 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
diff -u -r 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-08 15:29:04.310642072 +0000
@@ -43,6 +43,10 @@
 #include <stdbool.h>
 #endif
 
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+#include <sys/uio.h>
+#endif
+
 
 #ifdef MHD_PANIC
 /* Override any defined MHD_PANIC macro with proper one */
@@ -450,6 +454,14 @@
    */
   bool is_pipe;
 
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+  struct iovec *data_iov;
+  int data_iovcnt;
+  struct iovec data_iov_tr;
+  struct iovec *data_iov_left;
+  int data_iovcnt_left;
+  MHD_IOVContentReaderFreeCallback data_iov_free;
+#endif
 };
 
 
@@ -1301,6 +1313,15 @@
                     char *uri);
 
 
+struct MHD_QueuedConn {
+  MHD_socket sock;
+  struct sockaddr *addr;
+  socklen_t addr_len;
+  bool sk_nonbl;
+  struct MHD_QueuedConn *next;
+};
+
+
 /**
  * State kept for each MHD daemon.  All connections are kept in two
  * doubly-linked lists.  The first one reflects the state of the
@@ -1850,6 +1871,11 @@
    * The size of queue for listen socket.
    */
   unsigned int listen_backlog_size;
+
+  struct MHD_QueuedConn *qconn_head;
+  struct MHD_QueuedConn *qconn_tail;
+
+  MHD_mutex_ qconn_mutex;
 };
 
 
diff -u -r 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-08 15:29:04.310642072 +0000
@@ -1250,3 +1250,171 @@
 
 
 #endif /* _MHD_HAVE_SENDFILE */
+
+
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+static ssize_t
+send_iov_nontls (struct MHD_Connection *connection,
+                 struct iovec *iov,
+                 int iovcnt)
+{
+  ssize_t ret;
+#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
+  /* Copy in the iovec, offsetting as needed for previous partial sends. */
+  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;
+}
+
+#ifdef HTTPS_SUPPORT
+
+static ssize_t
+send_iov_tls (struct MHD_Connection *connection,
+              struct iovec *iov,
+              int iovcnt)
+{
+  ssize_t res;
+  int i;
+
+  /* Send one iovec element. */
+  res = gnutls_record_send (connection->tls_session,
+                            iov[0].iov_base,
+                            iov[0].iov_len);
+  if ( (GNUTLS_E_AGAIN == res) ||
+       (GNUTLS_E_INTERRUPTED == res) )
+  {
+#ifdef EPOLL_SUPPORT
+    if (GNUTLS_E_AGAIN == res)
+      connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif
+    return MHD_ERR_AGAIN_;
+  }
+  if (res < 0)
+  {
+    /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
+       disrupted); interpret as a hard error */
+    return MHD_ERR_NOTCONN_;
+  }
+  return res;
+}
+
+#endif /* HTTP_SUPPORT */
+
+ssize_t
+MHD_send_iovec_ (struct MHD_Connection *connection) {
+  struct MHD_Response *response = connection->response;
+  ssize_t ret, sz;
+  int i;
+#ifdef HTTPS_SUPPORT
+  const bool tls_conn = (connection->daemon->options & MHD_USE_TLS);
+#else  /* ! HTTPS_SUPPORT */
+  const bool tls_conn = false;
+#endif /* ! HTTPS_SUPPORT */
+
+  pre_send_setopt (connection, !tls_conn, false);
+
+#ifdef HTTPS_SUPPORT
+  if (0 != (connection->daemon->options & MHD_USE_TLS))
+  {
+    ret = send_iov_tls (connection,
+                        response->data_iov_left,
+                        response->data_iovcnt_left);
+  }
+  else
+#endif /* HTTPS_SUPPORT */
+  {
+    ret = send_iov_nontls(connection,
+                          response->data_iov_left,
+                          response->data_iovcnt_left);
+  }
+
+  /* This does not spark joy. */
+  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(struct 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 (0 == response->data_iovcnt_left)
+    {
+        post_send_setopt (connection, !tls_conn, true);
+    }
+  }
+
+  return ret;
+}
+
+#endif /* HAVE_SENDMSG || HAVE_WRITEV */
diff -u -r 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-08 15:29:04.314642224 +0000
@@ -111,4 +111,11 @@
 
 #endif
 
+
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+ssize_t
+MHD_send_iovec_ (struct MHD_Connection *connection);
+
+#endif
+
 #endif /* MHD_SEND_H */
diff -u -r 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-08 15:29:04.314642224 +0000
@@ -56,6 +56,11 @@
 #endif /* _WIN32 */
 
 
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+#include <sys/uio.h>
+#endif
+
+
 /**
  * Size of single file read operation for
  * file-backed responses.
@@ -846,6 +851,74 @@
 }
 
 
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+/**
+ * Create a response object from an iovec.  The response object can be
+ * extended with header information and then be used any number of times.
+ *
+ * @param iov I/O vector for response data
+ * @param iovcnt number of elements in iov
+ * @param cls extra argument passed to free_cb
+ * @param free_cb callback to clean up any data associated with iov when
+ *        the response is destroyed.
+ * @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 iovec *iov,
+                                int iovcnt,
+                                void *cls,
+                                MHD_IOVContentReaderFreeCallback free_cb)
+{
+  struct MHD_Response *response;
+  void *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(struct iovec))))
+  {
+#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
+    MHD_mutex_destroy_chk_ (&response->mutex);
+#endif
+    free(response);
+    return NULL;
+  }
+
+  response->data_iov = (struct iovec *)tmp;
+  response->data_iovcnt = iovcnt;
+  response->data_iov_left = tmp;
+  response->data_iovcnt_left = iovcnt;
+  response->crc_cls = cls;
+  response->data_iov_free = free_cb;
+  memcpy(response->data_iov, iov, iovcnt * sizeof(struct iovec));
+
+  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;
+}
+
+
+#endif /* HAVE_SENDMSG || HAVE_WRITEV */
+
+
 #ifdef UPGRADE_SUPPORT
 /**
  * This connection-specific callback is provided by MHD to
@@ -1287,6 +1360,18 @@
 #endif
   if (NULL != response->crfc)
     response->crfc (response->crc_cls);
+
+#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
+  if (NULL != response->data_iov)
+  {
+    if (NULL != response->data_iov_free)
+      response->data_iov_free (response->data_iov,
+                               response->data_iovcnt,
+                               response->crc_cls);
+    free(response->data_iov);
+  }
+#endif
+
   while (NULL != response->first_header)
   {
     pos = response->first_header;
