소스 검색

more work on mhd2 api implementation

Christian Grothoff 8 년 전
부모
커밋
e77fce2749

+ 24 - 11
src/include/microhttpd2.h

@@ -1,6 +1,6 @@
 /*
      This file is part of libmicrohttpd
-     Copyright (C) 2006-2017 Christian Grothoff, Karlson2k (Evgeny Grin)
+     Copyright (C) 2006-2018 Christian Grothoff, Karlson2k (Evgeny Grin)
      (and other contributing authors)
 
      This library is free software; you can redistribute it and/or
@@ -23,8 +23,9 @@
  * Note that we do not indicate which of the OLD APIs
  * simply need to be kept vs. deprecated.
  *
+ *
  * The goal is to provide a basis for discussion!
- * None of this is implemented yet.
+ * Little of this is implemented yet.
  *
  * Main goals:
  * - simplify application callbacks by splitting header/upload/post
@@ -64,7 +65,13 @@
  *   supported (include the descriptive string) by using an enum;
  * - simplify API for common-case of one-shot responses by
  *   eliminating need for destroy response in most cases;
+ *
+ * TODO:
+ * - varargs in upgrade is still there and ugly (and not even used!)
+ * - migrate event loop apis (get fdset, timeout, MHD_run(), etc.)
  */
+#ifndef MICROHTTPD2_H
+#define MICROHTTPD2_H
 
 
 /**
@@ -1018,8 +1025,8 @@ MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon,
  * @return #MHD_SC_OK upon success; TODO: define failure modes
  */
 _MHD_EXTERN enum MHD_StatusCode
-  MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon,
-			       const char *dh);
+MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon,
+			     const char *dh);
 
 
 /**
@@ -1356,17 +1363,16 @@ MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon,
 
 
 /**
- * Generate option to set a custom timeout for the given connection.
- * Specified as the number of seconds.  Use zero for no timeout.  If
- * timeout was set to zero (or unset) before, setting of a new value
- * by MHD_connection_set_option() will reset timeout timer.
+ * Set custom timeout for the given connection.
+ * Specified as the number of seconds.  Use zero for no timeout.  
+ * Calling this function will reset timeout timer.
  *
  * @param connection connection to configure timeout for
  * @param timeout_s new timeout in seconds
  */
-_MHD_EXTERN struct MHD_ConnectionOption
-MHD_connection_timeout (struct MHD_Connection *connection,
-			unsigned int timeout_s);
+_MHD_EXTERN void
+MHD_connection_set_timeout (struct MHD_Connection *connection,
+			    unsigned int timeout_s);
 
 
 /* **************** Request handling functions ***************** */
@@ -1792,6 +1798,9 @@ struct MHD_UpgradeResponseHandle;
  * It allows applications to perform 'special' actions on
  * the underlying socket from the upgrade.
  *
+ * FIXME: this API still uses the untyped, ugly varargs.
+ * Should we not modernize this one as well?
+ *
  * @param urh the handle identifying the connection to perform
  *            the upgrade @a action on.
  * @param operation which operation should be performed
@@ -1987,6 +1996,7 @@ MHD_response_get_header (struct MHD_Response *response,
 
 /* ************Upload and PostProcessor functions ********************** */
 
+
 /**
  * Action telling MHD to continue processing the upload.
  *
@@ -2493,3 +2503,6 @@ MHD_daemon_get_information_sz (struct MHD_Daemon *daemon,
                                    info_type,    \
                                    return_value) \
 	MHD_daemon_get_information_sz((daemon), (info_type), (return_value), sizeof(union MHD_DaemonInformation));
+
+
+#endif

+ 60 - 0
src/lib/action_continue.c

@@ -0,0 +1,60 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/action_continue.c
+ * @brief implementation of MHD_action_continue()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * The continue action is being run.  Continue
+ * handling the upload.
+ *
+ * @param cls NULL
+ * @param request the request to apply the action to
+ */
+static void
+cont_action (void *cls,
+	     struct MHD_Request *request)
+{
+  /* not sure yet, but this function body may 
+     just legitimately stay empty... */
+}
+
+
+/**
+ * Action telling MHD to continue processing the upload.
+ *
+ * @return action operation, never NULL
+ */
+struct MHD_Action *
+MHD_action_continue (void)
+{
+  static MHD_Action acont = {
+    .action = &cont_action,
+    .action_cls = NULL
+  };
+
+  return &acont;
+}
+
+/* end of action_continue.c */

+ 130 - 0
src/lib/action_from_response.c

@@ -0,0 +1,130 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/action_from_response.c
+ * @brief implementation of #MHD_action_from_response()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * A response was given as the desired action for a @a request.
+ * Queue the response for the request.
+ *
+ * @param cls the `struct MHD_Response`
+ * @param request the request we are processing
+ */
+static void
+response_action (void *cls,
+		 struct MHD_Request *request)
+{
+  struct MHD_Response *response = cls;
+  struct MHD_Daemon *daemon = response->daemon;
+
+  if (daemon->shutdown)
+    return MHD_YES; /* If daemon was shut down in parallel,
+                     * response will be aborted now or on later stage. */
+
+#ifdef UPGRADE_SUPPORT
+  if ( (NULL != response->upgrade_handler) &&
+       (0 == (daemon->options & MHD_ALLOW_UPGRADE)) )
+    {
+#ifdef HAVE_MESSAGES
+      MHD_DLOG (daemon,
+                _("Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n"));
+#endif
+      return MHD_NO;
+    }
+#endif /* UPGRADE_SUPPORT */
+  request->response = response;
+#if defined(_MHD_HAVE_SENDFILE)
+  if ( (-1 == response->fd)
+#if HTTPS_SUPPORT
+       || (NULL != daemon->tls_api)
+#endif
+       )
+    request->resp_sender = MHD_resp_sender_std;
+  else
+    request->resp_sender = MHD_resp_sender_sendfile;
+#endif /* _MHD_HAVE_SENDFILE */
+
+  if ( ( (NULL != request->method) &&
+         (MHD_str_equal_caseless_ (request->method,
+                                   MHD_HTTP_METHOD_HEAD)) ) ||
+       (MHD_HTTP_OK > response->status_code) ||
+       (MHD_HTTP_NO_CONTENT == response->status_code) ||
+       (MHD_HTTP_NOT_MODIFIED == response->status_code) )
+    {
+      /* if this is a "HEAD" request, or a status code for
+         which a body is not allowed, pretend that we
+         have already sent the full message body. */
+      request->response_write_position = response->total_size;
+    }
+  if ( (MHD_REQUEST_HEADERS_PROCESSED == request->state) &&
+       (NULL != connection->method) &&
+       ( (MHD_str_equal_caseless_ (request->method,
+                                   MHD_HTTP_METHOD_POST)) ||
+	 (MHD_str_equal_caseless_ (request->method,
+                                   MHD_HTTP_METHOD_PUT))) )
+    {
+      /* response was queued "early", refuse to read body / footers or
+         further requests! */
+      connection->read_closed = true;
+      request->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+    }
+  if (! request->in_idle)
+    (void) MHD_connection_handle_idle (connection);
+}
+
+
+/**
+ * Converts a @a response to an action.  If @a consume
+ * is set, the reference to the @a response is consumed
+ * by the conversion. If @a consume is #MHD_NO, then
+ * the response can be converted to actions in the future.
+ * However, the @a response is frozen by this step and
+ * must no longer be modified (i.e. by setting headers).
+ *
+ * @param response response to convert, not NULL
+ * @param destroy_after_use should the response object be consumed?
+ * @return corresponding action, never returns NULL
+ *
+ * Implementation note: internally, this is largely just
+ * a cast (and possibly an RC increment operation),
+ * as a response *is* an action.  As no memory is
+ * allocated, this operation cannot fail.
+ */
+_MHD_EXTERN struct MHD_Action *
+MHD_action_from_response (struct MHD_Response *response,
+			  enum MHD_bool destroy_after_use)
+{
+  response->action.action = &response_action;
+  response->action.action_cls = response;
+  if (! destroy_after_use)
+    {
+      MHD_mutex_lock_chk_ (&response->mutex);
+      response->reference_count++;
+      MHD_mutex_unlock_chk_ (&response->mutex);
+    }
+  return &response->action;
+}
+
+/* end of action_from_response */

+ 61 - 0
src/lib/action_parse_post.c

@@ -0,0 +1,61 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/action_parse_post.c
+ * @brief implementation of MHD_action_parse_post()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+
+/**
+ * Create an action that parses a POST request.
+ *
+ * This action can be used to (incrementally) parse the data portion
+ * of a POST request.  Note that some buggy browsers fail to set the
+ * encoding type.  If you want to support those, you may have to call
+ * #MHD_set_connection_value with the proper encoding type before
+ * returning this action (if no supported encoding type is detected,
+ * returning this action will cause a bad request to be returned to
+ * the client).
+ *
+ * @param buffer_size maximum number of bytes to use for
+ *        internal buffering (used only for the parsing,
+ *        specifically the parsing of the keys).  A
+ *        tiny value (256-1024) should be sufficient.
+ *        Do NOT use a value smaller than 256.  For good
+ *        performance, use 32 or 64k (i.e. 65536).
+ * @param iter iterator to be called with the parsed data,
+ *        Must NOT be NULL.
+ * @param iter_cls first argument to @a iter
+ * @return NULL on error (out of memory, unsupported encoding),
+ *         otherwise a PP handle
+ * @ingroup request
+ */
+struct MHD_Action *
+MHD_action_parse_post (size_t buffer_size,
+		       MHD_PostDataIterator iter,
+		       void *iter_cls)
+{
+  return NULL; /* not yet implemented */
+}
+
+/* end of action_parse_post.c */

+ 92 - 0
src/lib/action_process_upload.c

@@ -0,0 +1,92 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/action_process_upload.c
+ * @brief implementation of MHD_action_process_upload()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Internal details about an upload action.
+ */
+struct UploadAction
+{
+  /**
+   * An upload action is an action. This field
+   * must come first!
+   */
+  struct MHD_Action action;
+
+  MHD_UploadCallback uc;
+
+  void *uc_cls;
+
+};
+
+
+/**
+ * The application wants to process uploaded data for
+ * the given request. Do it!
+ *
+ * @param cls the `struct UploadAction` with the
+ *    function we are to call for upload data
+ * @param request the request for which we are to process 
+ *    upload data
+ */
+static void
+upload_action (void *cls,
+	       struct MHD_Request *request)
+{
+  struct UploadAction *ua = cls;
+
+  (void) ua;
+  // FIXME: implement!
+}
+
+
+/**
+ * Create an action that handles an upload.
+ *
+ * @param uc function to call with uploaded data
+ * @param uc_cls closure for @a uc
+ * @return NULL on error (out of memory)
+ * @ingroup action
+ */
+struct MHD_Action *
+MHD_action_process_upload (MHD_UploadCallback uc,
+			   void *uc_cls)
+{
+  struct UploadAction *ua;
+
+  if (NULL == (ua = malloc (sizeof (struct UploadAction))))
+    return NULL;
+  ua->action = &upload_action;
+  ua->action_cls = ua;
+  ua->uc = uc;
+  ua->uc_cls = uc_cls;
+  return ua;
+}
+
+
+/* end of action_process_upload.c */
+
+

+ 132 - 0
src/lib/action_suspend.c

@@ -0,0 +1,132 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/action_suspend.c
+ * @brief implementation of MHD_action_suspend()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * The suspend action is being run.  Suspend handling
+ * of the given request.
+ *
+ * @param cls NULL
+ * @param request the request to apply the action to
+ */
+static void
+suspend_action (void *cls,
+		struct MHD_Request *request)
+{
+  struct MHD_Daemon *daemon = connection->daemon;
+
+  MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
+  if (connection->resuming)
+    {
+      /* suspending again while we didn't even complete resuming yet */
+      connection->resuming = false;
+      MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+      return;
+    }
+  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    {
+      if (connection->connection_timeout == daemon->connection_timeout)
+        XDLL_remove (daemon->normal_timeout_head,
+                     daemon->normal_timeout_tail,
+                     connection);
+      else
+        XDLL_remove (daemon->manual_timeout_head,
+                     daemon->manual_timeout_tail,
+                     connection);
+    }
+  DLL_remove (daemon->connections_head,
+              daemon->connections_tail,
+              connection);
+  mhd_assert (! connection->suspended);
+  DLL_insert (daemon->suspended_connections_head,
+              daemon->suspended_connections_tail,
+              connection);
+  connection->suspended = true;
+#ifdef EPOLL_SUPPORT
+  if (MHD_ELS_EPOLL == daemon->event_loop_syscall)
+    {
+      if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
+        {
+          EDLL_remove (daemon->eready_head,
+                       daemon->eready_tail,
+                       connection);
+          connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL;
+        }
+      if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET))
+        {
+          if (0 != epoll_ctl (daemon->epoll_fd,
+                              EPOLL_CTL_DEL,
+                              connection->socket_fd,
+                              NULL))
+            MHD_PANIC (_("Failed to remove FD from epoll set\n"));
+          connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET;
+        }
+      connection->epoll_state |= MHD_EPOLL_STATE_SUSPENDED;
+    }
+#endif
+  MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+}
+
+
+/**
+ * Suspend handling of network data for a given request.  This can
+ * be used to dequeue a request from MHD's event loop for a while.
+ *
+ * If you use this API in conjunction with a internal select or a
+ * thread pool, you must set the option #MHD_USE_ITC to
+ * ensure that a resumed request is immediately processed by MHD.
+ *
+ * Suspended requests continue to count against the total number of
+ * requests allowed (per daemon, as well as per IP, if such limits
+ * are set).  Suspended requests will NOT time out; timeouts will
+ * restart when the request handling is resumed.  While a
+ * request is suspended, MHD will not detect disconnects by the
+ * client.
+ *
+ * The only safe time to suspend a request is from either a
+ * #MHD_RequestHeaderCallback, #MHD_UploadCallback, or a
+ * #MHD_RequestfetchResponseCallback.  Suspending a request
+ * at any other time will cause an assertion failure.
+ *
+ * Finally, it is an API violation to call #MHD_daemon_stop() while
+ * having suspended requests (this will at least create memory and
+ * socket leaks or lead to undefined behavior).  You must explicitly
+ * resume all requests before stopping the daemon.
+ *
+ * @return action to cause a request to be suspended.
+ */
+struct MHD_Action *
+MHD_action_suspend (void)
+{
+  static MHD_Action suspend = {
+    .action = &suspend_action,
+    .action_cls = NULL
+  };
+
+  return &suspend;
+}
+
+/* end of action_suspend.c */

+ 52 - 0
src/lib/connection_info.c

@@ -0,0 +1,52 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/connection_info.c
+ * @brief implementation of MHD_connection_get_information_sz()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Obtain information about the given connection.
+ * Use wrapper macro #MHD_connection_get_information() instead of direct use
+ * of this function.
+ *
+ * @param connection what connection to get information about
+ * @param info_type what information is desired?
+ * @param[out] return_value pointer to union where requested information will
+ *                          be stored
+ * @param return_value_size size of union MHD_ConnectionInformation at compile
+ *                          time
+ * @return #MHD_YES on success, #MHD_NO on error
+ *         (@a info_type is unknown, NULL pointer etc.)
+ * @ingroup specialized
+ */
+enum MHD_Bool
+MHD_connection_get_information_sz (struct MHD_Connection *connection,
+				   enum MHD_ConnectionInformationType info_type,
+				   union MHD_ConnectionInformation *return_value,
+				   size_t return_value_size)
+{
+  return MHD_NO; /* FIXME: not yet implemented */
+}
+
+/* end of connection_info.c */

+ 104 - 7
src/lib/connection_options.c

@@ -1,16 +1,113 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/connection_options.c
+ * @brief functions to set per-connection options
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
 
 /**
- * Generate option to set a custom timeout for the given connection.
- * Specified as the number of seconds.  Use zero for no timeout.  If
- * timeout was set to zero (or unset) before, setting of a new value
- * by MHD_connection_set_option() will reset timeout timer.
+ * Set custom timeout for the given connection.  Specified as the
+ * number of seconds.  Use zero for no timeout.  Calling this function
+ * will reset timeout timer.
  *
  * @param connection connection to configure timeout for
  * @param timeout_s new timeout in seconds
  */
-struct MHD_ConnectionOption
-MHD_connection_timeout (struct MHD_Connection *connection,
-			unsigned int timeout_s);
+void
+MHD_connection_set_timeout (struct MHD_Connection *connection,
+			    unsigned int timeout_s)
+{
+  struct MHD_Daemon *daemon = connection->daemon;
+  
+  connection->last_activity = MHD_monotonic_sec_counter();
+  if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model)
+    {
+      /* Simple case, no need to lock to update DLLs */
+      connection->connection_timeout = (time_t) timeout_s;
+      return;
+    }
+  MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
+  if (! connection->suspended)
+    {
+      if (connection->connection_timeout == daemon->connection_timeout)
+	XDLL_remove (daemon->normal_timeout_head,
+		     daemon->normal_timeout_tail,
+		     connection);
+      else
+	XDLL_remove (daemon->manual_timeout_head,
+		     daemon->manual_timeout_tail,
+		     connection);
+    }  
+  connection->connection_timeout = (time_t) timeout_s;
+  if (! connection->suspended)
+    {
+      if (connection->connection_timeout == daemon->connection_timeout)
+	XDLL_insert (daemon->normal_timeout_head,
+		     daemon->normal_timeout_tail,
+		     connection);
+      else
+	XDLL_insert (daemon->manual_timeout_head,
+		     daemon->manual_timeout_tail,
+		     connection);
+    }
+  MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+}
+
+
+/**
+ * Update the 'last_activity' field of the connection to the current
+ * time and move the connection to the head of the 'normal_timeout'
+ * list if the timeout for the connection uses the default value.
+ *
+ * @param connection the connection that saw some activity
+ */
+void
+MHD_update_last_activity_ (struct MHD_Connection *connection)
+{
+  struct MHD_Daemon *daemon = connection->daemon;
+
+  if (0 == connection->connection_timeout)
+    return; /* Skip update of activity for connections
+               without timeout timer. */
+  if (connection->suspended)
+    return; /* no activity on suspended connections */
+
+  connection->last_activity = MHD_monotonic_sec_counter();
+  if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model)
+    return; /* each connection has personal timeout */
 
+  if (connection->connection_timeout != daemon->connection_timeout)
+    return; /* custom timeout, no need to move it in "normal" DLL */
 
+  MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
+  /* move connection to head of timeout list (by remove + add operation) */
+  XDLL_remove (daemon->normal_timeout_head,
+	       daemon->normal_timeout_tail,
+	       connection);
+  XDLL_insert (daemon->normal_timeout_head,
+	       daemon->normal_timeout_tail,
+	       connection);
+  MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+}
 
+/* end of connection_options.c */

+ 45 - 10
src/lib/daemon_info.c

@@ -1,20 +1,52 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
 
 /**
- * Obtain information about the given daemon
- * (not fully implemented!).
+ * @file lib/daemon_info.c
+ * @brief implementation of MHD_daemon_get_information_sz()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Obtain information about the given daemon.
+ * Use wrapper macro #MHD_daemon_get_information() instead of direct use
+ * of this function.
  *
  * @param daemon what daemon to get information about
  * @param info_type what information is desired?
- * @param ... depends on @a info_type
- * @return NULL if this information is not available
- *         (or if the @a info_type is unknown)
+ * @param[out] return_value pointer to union where requested information will
+ *                          be stored
+ * @param return_value_size size of union MHD_DaemonInformation at compile
+ *                          time
+ * @return #MHD_YES on success, #MHD_NO on error
+ *         (@a info_type is unknown, NULL pointer etc.)
  * @ingroup specialized
  */
-const union MHD_DaemonInfo *
-MHD_get_daemon_info (struct MHD_Daemon *daemon,
-		     enum MHD_DaemonInfoType info_type,
-		     ...)
+enum MHD_Bool
+MHD_daemon_get_information_sz (struct MHD_Daemon *daemon,
+			       enum MHD_DaemonInformationType info_type,
+			       union MHD_DaemonInformation *return_value,
+			       size_t return_value_size)
 {
+#if OLD
   if (NULL == daemon)
     return NULL;
   switch (info_type)
@@ -55,6 +87,9 @@ MHD_get_daemon_info (struct MHD_Daemon *daemon,
     default:
       return NULL;
     }
+#else
+  return MHD_NO;
+#endif
 }
 
-
+/* end of daemon_info.c */

+ 3 - 3
src/lib/daemon.c → src/lib/daemon_start.c

@@ -19,7 +19,7 @@
 
 /**
  * @file lib/daemon.c
- * @brief main functions to start a daemon
+ * @brief functions to start a daemon
  * @author Christian Grothoff
  */
 #include "internal.h"
@@ -642,8 +642,8 @@ setup_thread_pool (struct MHD_Daemon *daemon)
   enum MHD_StatusCode sc;
 
   /* Allocate memory for pooled objects */
-  daemon->worker_pool = calloc (daemon->threading_model,
-				sizeof (struct MHD_Daemon));
+  daemon->worker_pool = MHD_calloc_ (daemon->threading_model,
+				     sizeof (struct MHD_Daemon));
   if (NULL == daemon->worker_pool)
     return MHD_SC_THREAD_POOL_MALLOC_FAILURE;
   

+ 25 - 0
src/lib/init.c

@@ -1,3 +1,28 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/init.c
+ * @brief initialization routines
+ * @author Christian Grothoff
+ */
+#include "internal.h"
 #include "init.h"
 
 

+ 25 - 0
src/lib/init.h

@@ -1,3 +1,28 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/init.h
+ * @brief functions to initialize library
+ * @author Christian Grothoff
+ */
+#include "internal.h"
 
 
 #ifndef INIT_H

+ 165 - 19
src/lib/internal.h

@@ -561,12 +561,6 @@ struct MHD_Request
    */
   enum MHD_RequestEventLoopInfo event_loop_info;
 
-  /**
-   * HTTP response code.  Only valid if response object
-   * is already set.
-   */
-  unsigned int responseCode;
-
   /**
    * Did we ever call the "default_handler" on this request?  (this
    * flag will determine if we call the #MHD_OPTION_NOTIFY_COMPLETED
@@ -594,16 +588,6 @@ struct MHD_Request
    * be set to #MHD_NO again (before the final call to the handler).
    */
   bool have_chunked_upload;
-
-  /**
-   * Is the request suspended?
-   */
-  bool suspended;
-
-  /**
-   * Is the request wanting to resume?
-   */
-  bool resuming;
 };
 
 
@@ -660,6 +644,15 @@ struct MHD_Connection
    */
   struct MHD_Request request;
 
+  /**
+   * Is the connection suspended?
+   */
+  bool suspended;
+
+  /**
+   * Is the connection wanting to resume?
+   */
+  bool resuming;
 
   /**
    * Set to `true` if the thread has been joined.
@@ -679,8 +672,7 @@ struct MHD_Connection
    */
   bool read_closed;
 
-
-    /**
+  /**
    * Length of the foreign address.
    */
   socklen_t addr_len;
@@ -998,12 +990,166 @@ struct MHD_Daemon
    */
   bool allow_address_reuse;
 
-  
+    
+};
+
+
+/**
+ * Action function implementing some action to be
+ * performed on a request.
+ *
+ * @param cls action-specfic closure
+ * @param request the request on which the action is to be performed
+ */
+typedef void
+(*ActionCallback) (void *cls,
+		   const struct MHD_Request *request);
+
+
+/**
+ * Actions are returned by the application to drive the request
+ * handling of MHD.
+ */
+struct MHD_Action
+{
+
+  /**
+   * Function to call for the action.
+   */
+  ActionCallback action;
+
+  /**
+   * Closure for @a action
+   */ 
+  void *action_cls;
   
 };
 
 
+/**
+ * Representation of an HTTP response.
+ */
+struct MHD_Response
+{
+
+  /**
+   * A response *is* an action. See also
+   * #MHD_action_from_response().   Hence this field
+   * must be the first field in a response!
+   */
+  struct MHD_Action action;
+  
+  /**
+   * Headers to send for the response.  Initially
+   * the linked list is created in inverse order;
+   * the order should be inverted before sending!
+   */
+  struct MHD_HTTP_Header *first_header;
+
+  /**
+   * Buffer pointing to data that we are supposed
+   * to send as a response.
+   */
+  char *data;
+
+  /**
+   * Closure to give to the content reader @e crc
+   * and content reader free callback @e crfc.
+   */
+  void *crc_cls;
+
+  /**
+   * How do we get more data?  NULL if we are
+   * given all of the data up front.
+   */
+  MHD_ContentReaderCallback crc;
+
+  /**
+   * NULL if data must not be freed, otherwise
+   * either user-specified callback or "&free".
+   */
+  MHD_ContentReaderFreeCallback crfc;
+
+  /**
+   * Function to call once MHD is finished with 
+   * the request, may be NULL.
+   */
+  MHD_RequestTerminationCallback termination_cb;
+
+  /**
+   * Closure for @e termination_cb.
+   */
+  void *termination_cb_cls;
+  
+#ifdef UPGRADE_SUPPORT
+  /**
+   * Application function to call once we are done sending the headers
+   * of the response; NULL unless this is a response created with
+   * #MHD_create_response_for_upgrade().
+   */
+  MHD_UpgradeHandler upgrade_handler;
+
+  /**
+   * Closure for @e uh.
+   */
+  void *upgrade_handler_cls;
+#endif /* UPGRADE_SUPPORT */
+
+  /**
+   * Mutex to synchronize access to @e data, @e size and
+   * @e reference_count.
+   */
+  MHD_mutex_ mutex;
+
+  /**
+   * Set to #MHD_SIZE_UNKNOWN if size is not known.
+   */
+  uint64_t total_size;
+
+  /**
+   * At what offset in the stream is the
+   * beginning of @e data located?
+   */
+  uint64_t data_start;
+
+  /**
+   * Offset to start reading from when using @e fd.
+   */
+  uint64_t fd_off;
+
+  /**
+   * Number of bytes ready in @e data (buffer may be larger
+   * than what is filled with payload).
+   */
+  size_t data_size;
+
+  /**
+   * Size of the data buffer @e data.
+   */
+  size_t data_buffer_size;
+
+  /**
+   * HTTP status code of the response.
+   */
+  enum MHD_HTTP_StatusCode status_code;
+  
+  /**
+   * Reference count for this response.  Free once the counter hits
+   * zero.
+   */
+  unsigned int reference_count;
 
+  /**
+   * File-descriptor if this response is FD-backed.
+   */
+  int fd;
+
+  /**
+   * Only respond in HTTP 1.0 mode.
+   */
+  bool v10_only;
+  
+};
 
 
 

+ 25 - 0
src/lib/panic.c

@@ -1,3 +1,28 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/panic.c
+ * @brief functions to panic (abort)
+ * @author Christian Grothoff
+ */
+#include "internal.h"
 
 
 /**

+ 53 - 0
src/lib/request_info.c

@@ -0,0 +1,53 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/request_info.c
+ * @brief implementation of MHD_request_get_information_sz()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Obtain information about the given request.
+ * Use wrapper macro #MHD_request_get_information() instead of direct use
+ * of this function.
+ *
+ * @param request what request to get information about
+ * @param info_type what information is desired?
+ * @param[out] return_value pointer to union where requested information will
+ *                          be stored
+ * @param return_value_size size of union MHD_RequestInformation at compile
+ *                          time
+ * @return #MHD_YES on success, #MHD_NO on error
+ *         (@a info_type is unknown, NULL pointer etc.)
+ * @ingroup specialized
+ */
+enum MHD_Bool
+MHD_request_get_information_sz (struct MHD_Request *request,
+			        enum MHD_RequestInformationType info_type,
+			        union MHD_RequestInformation *return_value,
+			        size_t return_value_size)
+{
+  return MHD_NO; /* not implemented */
+}
+
+
+/* end of request_info.c */

+ 48 - 0
src/lib/request_resume.c

@@ -0,0 +1,48 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/request_resume.c
+ * @brief implementation of MHD_request_resume()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Resume handling of network data for suspended request.  It is
+ * safe to resume a suspended request at any time.  Calling this
+ * function on a request that was not previously suspended will
+ * result in undefined behavior.
+ *
+ * If you are using this function in ``external'' select mode, you must
+ * make sure to run #MHD_run() afterwards (before again calling
+ * #MHD_get_fdset(), as otherwise the change may not be reflected in
+ * the set returned by #MHD_get_fdset() and you may end up with a
+ * request that is stuck until the next network activity.
+ *
+ * @param request the request to resume
+ */
+void
+MHD_request_resume (struct MHD_Request *request)
+{
+  abort (); // not implemented...
+}
+
+/* end of request_resume.c */

+ 264 - 0
src/lib/response.c

@@ -0,0 +1,264 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/response.c
+ * @brief implementation of general response functions
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ * @author Karlson2k (Evgeny Grin)
+ */
+#include "internal.h"
+
+
+/**
+ * Add a header or footer line to the response.
+ *
+ * @param response response to add a header to
+ * @param kind header or footer
+ * @param header the header to add
+ * @param content value to add
+ * @return false on error (i.e. invalid header or content format).
+ */
+static bool
+add_response_entry (struct MHD_Response *response,
+		    enum MHD_ValueKind kind,
+		    const char *header,
+		    const char *content)
+{
+  struct MHD_HTTP_Header *hdr;
+
+  if ( (NULL == header) ||
+       (NULL == content) ||
+       (0 == header[0]) ||
+       (0 == content[0]) ||
+       (NULL != strchr (header, '\t')) ||
+       (NULL != strchr (header, '\r')) ||
+       (NULL != strchr (header, '\n')) ||
+       (NULL != strchr (content, '\t')) ||
+       (NULL != strchr (content, '\r')) ||
+       (NULL != strchr (content, '\n')) )
+    return false;
+  if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
+    return false;
+  if (NULL == (hdr->header = strdup (header)))
+    {
+      free (hdr);
+      return false;
+    }
+  if (NULL == (hdr->value = strdup (content)))
+    {
+      free (hdr->header);
+      free (hdr);
+      return false;
+    }
+  hdr->kind = kind;
+  hdr->next = response->first_header;
+  response->first_header = hdr;
+  return true;
+}
+
+
+/**
+ * Explicitly decrease reference counter of a response object.  If the
+ * counter hits zero, destroys a response object and associated
+ * resources.  Usually, this is implicitly done by converting a
+ * response to an action and returning the action to MHD.
+ *
+ * @param response response to decrement RC of
+ * @ingroup response
+ */
+void
+MHD_response_queue_for_destroy (struct MHD_Response *response)
+{
+  struct MHD_HTTP_Header *pos;
+
+  MHD_mutex_lock_chk_ (&response->mutex);
+  if (0 != --(response->reference_count))
+    {
+      MHD_mutex_unlock_chk_ (&response->mutex);
+      return;
+    }
+  MHD_mutex_unlock_chk_ (&response->mutex);
+  MHD_mutex_destroy_chk_ (&response->mutex);
+  if (NULL != response->crfc)
+    response->crfc (response->crc_cls);
+  while (NULL != response->first_header)
+    {
+      pos = response->first_header;
+      response->first_header = pos->next;
+      free (pos->header);
+      free (pos->value);
+      free (pos);
+    }
+  free (response);
+}
+
+
+/**
+ * Add a header line to the response.
+ *
+ * @param response response to add a header to
+ * @param header the header to add
+ * @param content value to add
+ * @return #MHD_NO on error (i.e. invalid header or content format),
+ *         or out of memory
+ * @ingroup response
+ */
+enum MHD_Bool
+MHD_response_add_header (struct MHD_Response *response,
+                         const char *header,
+			 const char *content)
+{
+  return add_response_entry (response,
+			     MHD_HEADER_KIND,
+			     header,
+			     content) ? MHD_TRUE : MHD_FALSE;
+}
+
+
+/**
+ * Add a tailer line to the response.
+ *
+ * @param response response to add a footer to
+ * @param footer the footer to add
+ * @param content value to add
+ * @return #MHD_NO on error (i.e. invalid footer or content format),
+ *         or out of memory
+ * @ingroup response
+ */
+enum MHD_Bool
+MHD_response_add_trailer (struct MHD_Response *response,
+                          const char *footer,
+                          const char *content)
+{
+  return add_response_entry (response,
+			     MHD_FOOTER_KIND,
+			     footer,
+			     content) ? MHD_TRUE : MHD_FALSE;
+}
+
+
+/**
+ * Delete a header (or footer) line from the response.
+ *
+ * @param response response to remove a header from
+ * @param header the header to delete
+ * @param content value to delete
+ * @return #MHD_NO on error (no such header known)
+ * @ingroup response
+ */
+enum MHD_Bool
+MHD_response_del_header (struct MHD_Response *response,
+                         const char *header,
+			 const char *content)
+{
+  struct MHD_HTTP_Header *pos;
+  struct MHD_HTTP_Header *prev;
+
+  if ( (NULL == header) ||
+       (NULL == content) )
+    return MHD_NO;
+  prev = NULL;
+  pos = response->first_header;
+  while (NULL != pos)
+    {
+      if ((0 == strcmp (header,
+                        pos->header)) &&
+          (0 == strcmp (content,
+                        pos->value)))
+        {
+          free (pos->header);
+          free (pos->value);
+          if (NULL == prev)
+            response->first_header = pos->next;
+          else
+            prev->next = pos->next;
+          free (pos);
+          return MHD_YES;
+        }
+      prev = pos;
+      pos = pos->next;
+    }
+  return MHD_NO;
+}
+
+
+/**
+ * Get all of the headers (and footers) added to a response.
+ *
+ * @param response response to query
+ * @param iterator callback to call on each header;
+ *        maybe NULL (then just count headers)
+ * @param iterator_cls extra argument to @a iterator
+ * @return number of entries iterated over
+ * @ingroup response
+ */
+unsigned int
+MHD_response_get_headers (struct MHD_Response *response,
+                          MHD_KeyValueIterator iterator,
+			  void *iterator_cls)
+{
+  unsigned int numHeaders = 0;
+  struct MHD_HTTP_Header *pos;
+
+  for (pos = response->first_header;
+       NULL != pos;
+       pos = pos->next)
+    {
+      numHeaders++;
+      if ( (NULL != iterator) &&
+	   (MHD_YES != iterator (iterator_cls,
+				 pos->kind,
+				 pos->header,
+				 pos->value)) )
+        break;
+    }
+  return numHeaders;
+}
+
+
+/**
+ * Get a particular header (or footer) from the response.
+ *
+ * @param response response to query
+ * @param key which header to get
+ * @return NULL if header does not exist
+ * @ingroup response
+ */
+const char *
+MHD_response_get_header (struct MHD_Response *response,
+			 const char *key)
+{
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == key)
+    return NULL;
+  for (pos = response->first_header;
+       NULL != pos;
+       pos = pos->next)
+    {
+      if (MHD_str_equal_caseless_ (pos->header,
+				   key))
+        return pos->value;
+    }
+  return NULL;
+}
+
+/* end of response.c */

+ 90 - 0
src/lib/response_for_upgrade.c

@@ -0,0 +1,90 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/response_for_upgrade.c
+ * @brief implementation of MHD_response_for_upgrade()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Create a response object that can be used for 101 UPGRADE
+ * responses, for example to implement WebSockets.  After sending the
+ * response, control over the data stream is given to the callback (which
+ * can then, for example, start some bi-directional communication).
+ * If the response is queued for multiple connections, the callback
+ * will be called for each connection.  The callback
+ * will ONLY be called after the response header was successfully passed
+ * to the OS; if there are communication errors before, the usual MHD
+ * connection error handling code will be performed.
+ *
+ * MHD will automatically set the correct HTTP status
+ * code (#MHD_HTTP_SWITCHING_PROTOCOLS).
+ * Setting correct HTTP headers for the upgrade must be done
+ * manually (this way, it is possible to implement most existing
+ * WebSocket versions using this API; in fact, this API might be useful
+ * for any protocol switch, not just WebSockets).  Note that
+ * draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this
+ * way as the header "HTTP/1.1 101 WebSocket Protocol Handshake"
+ * cannot be generated; instead, MHD will always produce "HTTP/1.1 101
+ * Switching Protocols" (if the response code 101 is used).
+ *
+ * As usual, the response object can be extended with header
+ * information and then be used any number of times (as long as the
+ * header information is not connection-specific).
+ *
+ * @param upgrade_handler function to call with the "upgraded" socket
+ * @param upgrade_handler_cls closure for @a upgrade_handler
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *
+MHD_response_for_upgrade (MHD_UpgradeHandler upgrade_handler,
+			  void *upgrade_handler_cls)
+{
+  struct MHD_Response *response;
+
+  mhd_assert (NULL != upgrade_handler);
+  response = MHD_calloc_ (1,
+			  sizeof (struct MHD_Response));
+  if (NULL == response)
+    return NULL;
+  if (! MHD_mutex_init_ (&response->mutex))
+    {
+      free (response);
+      return NULL;
+    }
+  response->upgrade_handler = upgrade_handler;
+  response->upgrade_handler_cls = upgrade_handler_cls;
+  response->status_code = MHD_HTTP_SWITCHING_PROTOCOLS;
+  response->total_size = MHD_SIZE_UNKNOWN;
+  response->reference_count = 1;
+  if (MHD_NO ==
+      MHD_add_response_header (response,
+                               MHD_HTTP_HEADER_CONNECTION,
+                               "Upgrade"))
+    {
+      MHD_destroy_response (response);
+      return NULL;
+    }
+  return response;
+}
+
+/* end of response_for_upgrade.c */

+ 88 - 0
src/lib/response_from_buffer.c

@@ -0,0 +1,88 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/response_from_buffer.c
+ * @brief implementation of MHD_response_from_buffer()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param sc status code to use for the response;
+ *           #MHD_HTTP_NO_CONTENT is only valid if @a size is 0;
+ * @param size size of the data portion of the response
+ * @param buffer size bytes containing the response's data portion
+ * @param mode flags for buffer management
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+struct MHD_Response *
+MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc,
+			  size_t size,
+			  void *buffer,
+			  enum MHD_ResponseMemoryMode mode)
+{
+  struct MHD_Response *response;
+  void *tmp;
+
+  mhd_assert ( (NULL != data) ||
+	       (0 == size) );
+  if (NULL ==
+      (response = MHD_calloc_ (1,
+			       sizeof (struct MHD_Response))))
+    return NULL;
+  response->fd = -1;
+  if (! MHD_mutex_init_ (&response->mutex))
+    {
+      free (response);
+      return NULL;
+    }
+  if ( (MHD_RESPMEM_MUST_COPY == mode) &&
+       (size > 0) )
+    {
+      if (NULL == (tmp = malloc (size)))
+        {
+          MHD_mutex_destroy_chk_ (&response->mutex);
+          free (response);
+          return NULL;
+        }
+      memcpy (tmp,
+	      data,
+	      size);
+      data = tmp;
+    }
+  if (MHD_RESPMEM_PERSISTENT != mode)
+    {
+      response->crfc = &free;
+      response->crc_cls = data;
+    }
+  response->status_code = sc;
+  response->reference_count = 1;
+  response->total_size = size;
+  response->data = data;
+  response->data_size = size;
+  return response;
+}
+
+/* end of response_from_buffer.c */

+ 80 - 0
src/lib/response_from_callback.c

@@ -0,0 +1,80 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/response_from_callback.c
+ * @brief implementation of MHD_response_from_callback()
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Create a response action.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param sc status code to return
+ * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown
+ * @param block_size preferred block size for querying crc (advisory only,
+ *                   MHD may still call @a crc using smaller chunks); this
+ *                   is essentially the buffer size used for IO, clients
+ *                   should pick a value that is appropriate for IO and
+ *                   memory performance requirements
+ * @param crc callback to use to obtain response data
+ * @param crc_cls extra argument to @a crc
+ * @param crfc callback to call to free @a crc_cls resources
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+struct MHD_Response *
+MHD_response_from_callback (enum MHD_HTTP_StatusCode sc,
+			    uint64_t size,
+			    size_t block_size,
+			    MHD_ContentReaderCallback crc,
+			    void *crc_cls,
+			    MHD_ContentReaderFreeCallback crfc)
+{
+  struct MHD_Response *response;
+
+  mhd_assert (NULL != crc);
+  mhd_assert (0 != block_size);
+  if (NULL ==
+      (response = MHD_calloc_ (1,
+			       sizeof (struct MHD_Response) +
+			       block_size)))
+    return NULL;
+  response->fd = -1;
+  response->status_code = sc;
+  response->data = (void *) &response[1];
+  response->data_buffer_size = block_size;
+  if (! MHD_mutex_init_ (&response->mutex))
+  {
+    free (response);
+    return NULL;
+  }
+  response->crc = crc;
+  response->crfc = crfc;
+  response->crc_cls = crc_cls;
+  response->reference_count = 1;
+  response->total_size = size;
+  return response;
+}
+
+
+/* end of response_from_callback.c */

+ 198 - 0
src/lib/response_from_fd.c

@@ -0,0 +1,198 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/response_from_fd.c
+ * @brief implementation of MHD_response_from_fd()
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ * @author Karlson2k (Evgeny Grin)
+ */
+#include "internal.h"
+
+
+/**
+ * Given a file descriptor, read data from the file
+ * to generate the response.
+ *
+ * @param cls pointer to the response
+ * @param pos offset in the file to access
+ * @param buf where to write the data
+ * @param max number of bytes to write at most
+ * @return number of bytes written
+ */
+static ssize_t
+file_reader (void *cls,
+             uint64_t pos,
+             char *buf,
+             size_t max)
+{
+  struct MHD_Response *response = cls;
+#if !defined(_WIN32) || defined(__CYGWIN__)
+  ssize_t n;
+#else  /* _WIN32 && !__CYGWIN__ */
+  const HANDLE fh = (HANDLE) _get_osfhandle (response->fd);
+#endif /* _WIN32 && !__CYGWIN__ */
+  const int64_t offset64 = (int64_t)(pos + response->fd_off);
+
+  if (offset64 < 0)
+    return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+  if (max > SSIZE_MAX)
+    max = SSIZE_MAX; /* Clamp to maximum return value. */
+
+#if defined(HAVE_PREAD64)
+  n = pread64 (response->fd,
+	       buf,
+	       max,
+	       offset64);
+#elif defined(HAVE_PREAD)
+  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
+       (offset64 > (uint64_t)INT32_MAX) )
+    return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
+
+  n = pread (response->fd,
+	     buf,
+	     max,
+	     (off_t) offset64);
+#else  /* ! HAVE_PREAD */
+#if defined(HAVE_LSEEK64)
+  if (lseek64 (response->fd,
+               offset64,
+               SEEK_SET) != offset64)
+    return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
+#else  /* ! HAVE_LSEEK64 */
+  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
+       (offset64 > (uint64_t)INT32_MAX) )
+    return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
+
+  if (lseek (response->fd,
+             (off_t) offset64,
+             SEEK_SET) != (off_t) offset64)
+    return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
+#endif /* ! HAVE_LSEEK64 */
+  n = read (response->fd,
+            buf,
+            max);
+
+#endif /* ! HAVE_PREAD */
+  if (0 == n)
+    return MHD_CONTENT_READER_END_OF_STREAM;
+  if (n < 0)
+    return MHD_CONTENT_READER_END_WITH_ERROR;
+  return n;
+#else /* _WIN32 && !__CYGWIN__ */
+  if (INVALID_HANDLE_VALUE == fh)
+    return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
+  else
+    {
+      OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
+      ULARGE_INTEGER pos_uli;
+      DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
+      DWORD resRead;
+
+      pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
+      f_ol.Offset = pos_uli.LowPart;
+      f_ol.OffsetHigh = pos_uli.HighPart;
+      if (! ReadFile (fh,
+		      (void*)buf,
+		      toRead,
+		      &resRead,
+		      &f_ol))
+        return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
+      if (0 == resRead)
+        return MHD_CONTENT_READER_END_OF_STREAM;
+      return (ssize_t) resRead;
+    }
+#endif /* _WIN32 && !__CYGWIN__ */
+}
+
+
+/**
+ * Destroy file reader context.  Closes the file
+ * descriptor.
+ *
+ * @param cls pointer to file descriptor
+ */
+static void
+free_callback (void *cls)
+{
+  struct MHD_Response *response = cls;
+
+  (void) close (response->fd);
+  response->fd = -1;
+}
+
+
+/**
+ * Create a response object based on an @a fd from which
+ * data is read.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param sc status code to return
+ * @param fd file descriptor referring to a file on disk with the
+ *        data; will be closed when response is destroyed;
+ *        fd should be in 'blocking' mode
+ * @param offset offset to start reading from in the file;
+ *        reading file beyond 2 GiB may be not supported by OS or
+ *        MHD build; see ::MHD_FEATURE_LARGE_FILE
+ * @param size size of the data portion of the response;
+ *        sizes larger than 2 GiB may be not supported by OS or
+ *        MHD build; see ::MHD_FEATURE_LARGE_FILE
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+struct MHD_Response *
+MHD_response_from_fd (enum MHD_HTTP_StatusCode sc,
+		      int fd,
+		      uint64_t offset,
+		      uint64_t size)
+{
+  struct MHD_Response *response;
+
+  mhd_assert (-1 != fd);
+#if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64)
+  if ( (sizeof (uint64_t) > sizeof (off_t)) &&
+       ( (size > (uint64_t)INT32_MAX) ||
+         (offset > (uint64_t)INT32_MAX) ||
+         ((size + offset) >= (uint64_t)INT32_MAX) ) )
+    return NULL;
+#endif
+  if ( ((int64_t) size < 0) ||
+       ((int64_t) offset < 0) ||
+       ((int64_t) (size + offset) < 0) )
+    return NULL;
+
+  response = MHD_response_from_callback (size,
+					 4 * 1024,
+					 &file_reader,
+					 NULL,
+					 &free_callback);
+  if (NULL == response)
+    return NULL;
+  response->fd = fd;
+  response->status_code = sc;
+  response->fd_off = offset;
+  response->crc_cls = response;
+  return response;
+}
+
+/* end of response_from_fd.c */
+

+ 61 - 0
src/lib/response_options.c

@@ -0,0 +1,61 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/response_option.c
+ * @brief implementation of response options
+ * @author Christian Grothoff
+ */
+#include "internal.h"
+
+
+/**
+ * Only respond in conservative HTTP 1.0-mode.  In
+ * particular, do not (automatically) sent "Connection" headers and
+ * always close the connection after generating the response.
+ *
+ * @param request the request for which we force HTTP 1.0 to be used
+ */
+void
+MHD_response_option_v10_only (struct MHD_Response *response)
+{
+  response->v10_only = true;
+}
+
+
+/**
+ * Set a function to be called once MHD is finished with the
+ * request.
+ *
+ * @param response which response to set the callback for
+ * @param termination_cb function to call
+ * @param termination_cb_cls closure for @e termination_cb
+ */
+void
+MHD_response_option_termination_callback (struct MHD_Response *response,
+					  MHD_RequestTerminationCallback termination_cb,
+					  void *termination_cb_cls)
+{
+  /* Q: should we assert termination_cb non-NULL? */
+  response->termination_cb = termination_cb;
+  response->termination_cb_cls = termination_cb_cls;
+}
+
+
+/* end of response_option.c */

+ 25 - 0
src/lib/version.c

@@ -1,3 +1,28 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/version.c
+ * @brief versioning and optional feature tests
+ * @author Christian Grothoff
+ */
+#include "internal.h"
 
 
 /**

+ 2 - 1
src/microhttpd/response.c

@@ -246,12 +246,13 @@ MHD_get_response_header (struct MHD_Response *response,
        NULL != pos;
        pos = pos->next)
     {
-      if ( MHD_str_equal_caseless_ (pos->header, key) )
+      if (MHD_str_equal_caseless_ (pos->header, key))
         return pos->value;
     }
   return NULL;
 }
 
+
 /**
  * Check whether response header contains particular token.
  *