2
0
Эх сурвалжийг харах

microhttpd2.h: preparation

Evgeny Grin (Karlson2k) 1 жил өмнө
parent
commit
83beaa825f
1 өөрчлөгдсөн 1586 нэмэгдсэн , 1223 устгасан
  1. 1586 1223
      src/include/microhttpd2.h

+ 1586 - 1223
src/include/microhttpd2.h

@@ -2614,1624 +2614,1987 @@ MHD_EXTERN_ void
 MHD_daemon_destroy (struct MHD_Daemon *daemon)
 MHD_FN_PAR_NONNULL_ALL_;
 
+/* ******************* External event loop ************************ */
 
-/* ********************* daemon options ************** */
-
-/**
- * Type of a callback function used for logging by MHD.
- *
- * @param cls closure
- * @param sc status code of the event
- * @param fm format string (`printf()`-style)
- * @param ap arguments to @a fm
- * @ingroup logging
- */
-typedef void
-(MHD_FN_PAR_NONNULL_(3)
- MHD_FN_PAR_CSTR_(3)
- *MHD_LoggingCallback)(void *cls,
-                       enum MHD_StatusCode sc,
-                       const char *fm,
-                       va_list ap);
-
-// FIXME: convert
 /**
- * Convenience macro used to disable logging.
+ * The network status of the socket.
+ * When set by MHD (by #MHD_get_watched_fds(), #MHD_get_watched_fds_update() and
+ * similar) it indicates a request to watch for specific socket state:
+ * readiness for receiving the data, readiness for sending the data and/or
+ * exception state of the socket.
+ * When set by application (and provided for #MHD_process_watched_fds() and
+ * similar) it must indicate the actual status of the socket.
  *
- * @param daemon which instance to disable logging for
- */
-#define MHD_daemon_disable_logging(daemon) \
-  MHD_daemon_set_logger ((daemon), \
-                         MHD_STATIC_CAST_(MHD_LoggingCallback,NULL),   \
-                         NULL)
-
-/**
- * Parameter for listen socket binding type
+ * Any actual state is a bitwise OR combination of #MHD_FD_STATE_RECV,
+ * #MHD_FD_STATE_SEND, #MHD_FD_STATE_EXCEPT.
+ * @ingroup event
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_DaemonOptionBindType
+enum MHD_FIXED_ENUM_ MHD_FdState
 {
   /**
-   * The listen socket bind to the networks address without sharing the address.
-   * Default.
-   */
-  MHD_DAEMON_OPTION_BIND_TYPE_NOT_SHARED = 0
-  ,
-  /**
-   * The listen socket bind to the networks address with sharing the address.
-   * Several sockets can bind to the same address.
+   * The socket is not ready for receiving or sending and
+   * does not have any exceptional state.
+   * The state never set by MHD, except de-registration of the sockets
+   * for #MHD_SocketRegistrationUpdateCallback().
    */
-  MHD_DAEMON_OPTION_BIND_TYPE_SHARED = 1
+  MHD_FD_STATE_NONE = 0
   ,
-  /**
-   * The list socket bind to the networks address in explicit exclusive mode.
-   * Ignored on platforms without support for the explicit exclusive socket use.
-   */
-  MHD_DAEMON_OPTION_BIND_TYPE_EXCLUSIVE = 2
-};
-
+  /* ** Three bit-flags ** */
 
-enum MHD_FIXED_ENUM_APP_SET_ MHD_DaemonOption
-{
-  /**
-   * Not a real option.
-   * Should not be used directly.
-   * This value indicates the end of the list of the options.
-   */
-  MHD_D_O_END = 0
-  ,
-  /**
-   * Suppresses use of "Date:" header.
-   * According to RFC should be used only if the system has no RTC.
-   * The "Date:" is not suppressed (the header is enabled) by default.
-   */
-  MHD_D_O_BOOL_SUPPRESS_DATE_HEADER = 100
-  ,
   /**
-   * Enable `turbo`.  Disables certain calls to `shutdown()`,
-   * enables aggressive non-blocking optimistic reads and
-   * other potentially unsafe optimisations.
-   * Most effects only happen with internal threads with epoll.
-   * The 'turbo' mode is not enabled (mode is disabled) by default.
+   * Indicates that socket should be watched for incoming data
+   * (when set by #MHD_get_watched_fds())
+   * / socket has incoming data ready to read (when used for
+   * #MHD_process_watched_fds())
    */
-  MHD_D_O_BOOL_TURBO = 102
-  ,
+  MHD_FD_STATE_RECV = 1 << 0,
   /**
-   * Disable some internal thread safety.
-   * Indicates that MHD daemon will be used by application in single-threaded
-   * mode only.  When this flag is set then application must call any MHD
-   * function only within a single thread.
-   * This flag turns off some internal thread-safety and allows MHD making
-   * some of the internal optimisations suitable only for single-threaded
-   * environment.
-   * Not compatible with any internal threads mode.
-   * Thread safety is not disabled (safety is enabled) by default.
+   * Indicates that socket should be watched for availability for sending
+   * (when set by #MHD_get_watched_fds())
+   * / socket has ability to send data (when used for
+   * #MHD_process_watched_fds())
    */
-  MHD_D_O_DISABLE_THREAD_SAFETY = 103
-  ,
+  MHD_FD_STATE_SEND = 1 << 1,
   /**
-   * You need to set this option if you want to disable use of HTTP "Upgrade".
-   * "Upgrade" may require usage of additional internal resources,
-   * which we can avoid providing if they will not be used.
-   *
-   * You should only use this function if you do not use "Upgrade" functionality
-   * and need a generally minor boost in performance.
-   * The "Upgrade" is not disallowed ("upgrade" is allowed) by default.
+   * Indicates that socket should be watched for disconnect, out-of-band
+   * data available or high priority data available (when set by
+   * #MHD_get_watched_fds())
+   * / socket has been disconnected, has out-of-band data available or
+   * has high priority data available (when used for
+   * #MHD_process_watched_fds()). This status must not include "remote
+   * peer shut down writing" status.
+   * Note: #MHD_get_watched_fds() always set it as exceptions must be
+   * always watched.
    */
-  MHD_D_O_BOOL_DISALLOW_UPGRADE = 104
-  ,
-  /**
-   * Disable #MHD_action_suspend() functionality.
-   *
-   * You should only use this function if you do not use suspend functionality
-   * and need a generally minor boost in performance.
-   * The suspend is not disallowed (suspend is allowed) by default.
+  MHD_FD_STATE_EXCEPT = 1 << 2,
+
+  /* The rest of the list is a bit-wise combination of three main
+   * states. Application may use three main states directly as
+   * a bit-mask instead of using of following values
    */
-  MHD_D_O_BOOL_DISALLOW_SUSPEND_RESUME
-  ,
+
   /**
-   * Use SHOUTcast.  This will cause *all* responses to begin
-   * with the SHOUTcast "ICY" line instead of "HTTP".
+   * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_SEND states.
    */
-  MHD_D_O_BOOL_ENABLE_SHOUTCAST
-  ,
+  MHD_FD_STATE_RECV_SEND = MHD_FD_STATE_RECV | MHD_FD_STATE_SEND,
   /**
-   * Disable converting plus ('+') character to space in GET
-   * parameters (URI part after '?').
-   * TODO: Add explanation, RFCs, HTML
+   * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states.
    */
-  MHD_D_O_BOOL_DISABLE_GET_PARAM_PLUS_AS_SPACE,
-
+  MHD_FD_STATE_RECV_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT,
   /**
-   * Bind to the given socket address.
+   * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states.
    */
-  MHD_D_O_SA
-  ,
+  MHD_FD_STATE_SEND_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT,
   /**
-   * If present true, allow reusing address:port socket (by using
-   * SO_REUSEPORT on most platform, or platform-specific ways).  If
-   * present and set to false, disallow reusing address:port socket
-   * (does nothing on most platform, but uses SO_EXCLUSIVEADDRUSE on
-   * Windows).
-   * Ineffective in conjunction with #MHD_daemon_listen_socket().
+   * Combination of #MHD_FD_STATE_RECV, #MHD_FD_STATE_SEND and
+   * #MHD_FD_STATE_EXCEPT states.
    */
-  MHD_D_O_BOOL_LISTEN_ALLOW_ADDRESS_REUSE
+  MHD_FD_STATE_RECV_SEND_EXCEPT = \
+    MHD_FD_STATE_RECV | MHD_FD_STATE_SEND | MHD_FD_STATE_EXCEPT
 };
 
-// FIXME: transform everything to option
-
 /**
- * Possible levels of enforcement for TCP_FASTOPEN.
+ * Checks whether specific @a state is enabled in @a var
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_TCPFastOpenType
-{
-  /**
-   * Disable use of TCP_FASTOPEN.
-   */
-  MHD_FOM_DISABLE = -1
-  ,
-  /**
-   * Enable TCP_FASTOPEN where supported.
-   * On GNU/Linux it works with a kernel >= 3.6.
-   * This is the default.
-   */
-  MHD_FOM_AUTO = 0
-  ,
-  /**
-   * Require TCP_FASTOPEN.
-   * Also causes #MHD_daemon_start() to fail if setting
-   * the option fails later.
-   */
-  MHD_FOM_REQUIRE = 1
-};
-
-
+#define MHD_FD_STATE_IS_SET(var,state)          \
+  (MHD_FD_STATE_NONE !=                         \
+   (((enum MHD_FdState) (var)) & ((enum MHD_FdState) (state))))
 
 /**
- * Address family to be used by MHD.
+ * Checks whether RECV is enabled in @a var
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_AddressFamily
-{
-  /**
-   * Option not given, do not listen at all
-   * (unless listen socket or address specified by
-   * other means).
-   */
-  MHD_AF_NONE = 0
-  ,
-  /**
-   * Pick "best" available method automatically.
-   */
-  MHD_AF_AUTO = 1
-  ,
-  /**
-   * Use IPv4.
-   */
-  MHD_AF_INET4 = 2
-  ,
-  /**
-   * Use IPv6.
-   */
-  MHD_AF_INET6 = 3
-  ,
-  /**
-   * Use dual stack.
-   */
-  MHD_AF_DUAL = 4
-};
+#define MHD_FD_STATE_IS_SET_RECV(var) \
+  MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_RECV)
+/**
+ * Checks whether SEND is enabled in @a var
+ */
+#define MHD_FD_STATE_IS_SET_SEND(var) \
+  MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_SEND)
+/**
+ * Checks whether EXCEPT is enabled in @a var
+ */
+#define MHD_FD_STATE_IS_SET_EXCEPT(var) \
+  MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_EXCEPT)
 
 
 /**
- * Bind to the given socket address.
- * Ineffective in conjunction with #MHD_daemon_listen_socket().
- *
- * @param[in,out] daemon which instance to configure the binding address for
- * @param sa address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6)
- *        or even a UNIX domain socket (AF_UNIX)
- * @param sa_len number of bytes in @a sa
- * @return #MHD_SC_OK on on success,
- *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
- *         #MHD_SC_FEATURE_DISABLED,
- *         #MHD_SC_FEATURE_NOT_AVAILABLE,
- *         #MHD_SC_OPTIONS_CONFLICT
+ * Enable specific @a state in @a var
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_bind_socket_address (struct MHD_Daemon *daemon,
-                                const struct sockaddr *sa,
-                                size_t sa_len)
-MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
-
-// TODO: Sort values and assign numbers
-enum MHD_DeamonOptionUInt
-{
-  /**
-   * Use the given backlog for the listen() call.
-   * Ineffective in conjunction with #MHD_daemon_listen_socket()
-   */
-  MHD_DAEMON_OPTION_UINT_LISTEN_BACKLOG,
-  /**
-   * Maximum number of (concurrent) network connections served
-   * by daemon
-   */
-  MHD_DAEMON_OPTION_UINT_GLOBAL_CONNECTION_LIMIT,
-  /**
-   * Limit on the number of (concurrent) network connections
-   * made to the server from the same IP address.
-   * Can be used to prevent one IP from taking over all of
-   * the allowed connections. If the same IP tries to establish
-   * more than the specified number of connections, they will
-   * be immediately rejected.
-   */
-  MHD_DAEMON_OPTION_UINT_IP_CONNECTION_LIMIT,
+#define MHD_FD_STATE_SET(var,state) \
+  (var) = (enum MHD_FdState) ((var) | (state))
+/**
+ * Enable RECV state in @a var
+ */
+#define MHD_FD_STATE_SET_RECV(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_RECV)
+/**
+ * Enable SEND state in @a var
+ */
+#define MHD_FD_STATE_SET_SEND(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_SEND)
+/**
+ * Enable EXCEPT state in @a var
+ */
+#define MHD_FD_STATE_SET_EXCEPT(var) \
+  MHD_FD_STATE_SET ((var),MHD_FD_STATE_EXCEPT)
 
-  /**
-   * After how many seconds of inactivity should a
-   * connection automatically be timed out?
-   * Use zero for no timeout, which is also the (unsafe!) default.
-   */
-  MHD_DAEMON_OPTION_UINT_DEFAULT_TIMEOUT,
+/**
+ * Clear/disable specific @a state in @a var
+ */
+#define MHD_FD_STATE_CLEAR(var,state) \
+  (var) = (enum MHD_FdState) ((var) & (((enum MHD_FdState))(~state)))
+/**
+ * Clear/disable RECV state in @a var
+ */
+#define MHD_FD_STATE_CLEAR_RECV(var) \
+  MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_RECV)
+/**
+ * Clear/disable SEND state in @a var
+ */
+#define MHD_FD_STATE_CLEAR_SEND(var) \
+  MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_SEND)
+/**
+ * Clear/disable EXCEPT state in @a var
+ */
+#define MHD_FD_STATE_CLEAR_EXCEPT(var) \
+  MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_EXCEPT)
 
-  /**
-   * The number of worker threads.
-   * Only useful if the selected threading mode
-   * is #MHD_TM_WORKER_THREADS.
-   * Zero number is silently ignored.
-   */
-  MHD_DAEMON_OPTION_UINT_NUM_WORKERS
 
-};
+/* Changes:
+ * + status update callback replaced with function
+ * + status update accepts array of updates
+ */
 
 /**
- * Set unsigned integer MHD option.
- *
- * @param[in,out] daemon which instance to set uint @a option for
- * @param option option to modify
- * @param value new value for the option
- * @return #MHD_SC_OK on on success,
- *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
- *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
- *         #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system
- *         #MHD_SC_OPTIONS_CONFLICT
+ * The context data to be used for updates of the socket state
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_option_uint (struct MHD_Daemon *daemon,
-                            enum MHD_DeamonOptionUInt option,
-                            unsigned int value)
-MHD_FN_PAR_NONNULL_ (1);
+struct MHD_EventUpdateContext;
 
-// FIXME: Alternative or additional implementation.
 
-struct MHD_DaemonOptioniUIntEntry
-{
-  /**
-   * The option to update the @a value
-   */
-  enum MHD_DeamonOptionUInt option;
-  /**
-   * The value to update for the @a option
-   */
-  unsigned int value;
-  // TODO: union
-};
+/* Define MHD_APP_SOCKET_CNTX_TYPE to the socket context type before
+ * including this header.
+ * This is optional, but improves the types safety.
+ * For example:
+ * #define MHD_APP_SOCKET_CNTX_TYPE struct my_structure
+ */
+#ifndef MHD_APP_SOCKET_CNTX_TYPE
+#  define MHD_APP_SOCKET_CNTX_TYPE void
+#endif
 
-#if 0
 /**
- * Set unsigned integer MHD options.
+ * The callback for registration/de-registration of the sockets to watch.
  *
- * @param[in,out] daemon which instance to set uint @a option for
- * @param num_entries the number of entries in the @a opt_val array
- *                    and in @a results (if not NULL)
- * @param[in] opt_val the array with options and values to modify
- * @param[out] results the results for the applying the options,
- *                     can be NULL,
- *                     if not NULL must have @a num_entries entries
- * @return #MHD_YES if all options have applied successfully
- *         #MHD_NO if at least single option failed (for more
- *         details check @a results)
+ * This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(),
+ * #MHD_daemon_add_connection().
+ *
+ * @param cls the closure
+ * @param fd the socket to watch
+ * @param watch_for the states of the @a fd to watch, if set to
+ *                  #MHD_FD_STATE_NONE the socket must be de-registred
+ * @param app_cntx_old the old application defined context for the socket,
+ *                     NULL if @a fd socket was not registered before
+ * @param ecb_cntx the context handle to be used
+ *                 with #MHD_daemon_event_update()
+ * @return NULL if error (to connection will be closed),
+ *         or the new socket context
+ * @ingroup event
  */
-MHD_EXTERN_ enum MHD_StatusCode // First failed // TODO: Document that rest may be used
-MHD_daemon_set_option_uint (
+typedef MHD_APP_SOCKET_CNTX_TYPE *
+(MHD_FN_PAR_NONNULL_(5)
+ *MHD_SocketRegistrationUpdateCallback)(
+  void *cls,
+  MHD_socket fd,
+  enum MHD_FdState watch_for,
+  MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old,
+  struct MHD_EventUpdateContext *ecb_cntx);
+
+
+/**
+ * Update the sockets state.
+ * Must be called for every socket that got state updated.
+ * For #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL mode should be called for each
+ * socket.
+ * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or
+ * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes.
+ * @param daemon the daemon handle
+ * @param ecb_cntx the context handle provided
+ *                 for #MHD_SocketRegistrationUpdateCallback
+ * @param fd_current_state the current state of the socket
+ */
+MHD_EXTERN_ void
+MHD_daemon_event_update (
   struct MHD_Daemon *daemon,
-  size_t num_entries,
-  struct MHD_DaemonOptioniUIntEntry opt_val[MHD_C99_ (static num_entries)])
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3);
-#endif
-// TODO: combine all types of options into single list with union
+  struct MHD_EventUpdateContext *ecb_cntx,
+  enum MHD_FdState fd_current_state)
+MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_NONNULL_(2);
+
+
 /**
- * Accept connections from the given socket.  Socket
- * must be a TCP or UNIX domain (stream) socket.
+ * Perform sockets registration, process registered network events.
  *
- * Unless MHD_INVALID_SOCKET is given, this disables
- * other listen options.
+ * This function first processes all registered (by MHD_daemon_event_update())
+ * network events (if any) and then calls #MHD_SocketRegistrationUpdateCallback
+ * callback for every socket that needs to be added/updated/removed.
  *
- * @param daemon daemon to set listen socket for
- * @param listen_socket listen socket to use,
- *        MHD_INVALID_SOCKET value will cause this call to be
- *        ignored (other binding options may still be effective)
- * @return #MHD_SC_OK on on success,
- *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
- *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
- *         #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system
- *         #MHD_SC_OPTIONS_CONFLICT
+ * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or
+ * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes.
+ *
+ * @param daemon the daemon handle
+ * @param[out] next_max_wait the optional pointer to receive the next maximum
+ *                           wait time in microseconds to be used for sockets
+ *                           polling function, can be NULL
+ * @return MHD_SC_OK on success,
+ *         error code otherwise
  */
 MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_listen_socket (struct MHD_Daemon *daemon,
-                          MHD_socket listen_socket)
-MHD_FN_PAR_NONNULL_ (1);
+MHD_deamon_process_reg_events(struct MHD_Daemon *daemon,
+                              uint_fast64_t *next_max_wait)
+MHD_FN_PAR_NONNULL_(1);
+
+/* ********************* daemon options ************** */
+
 
 /**
- * Event loop internal syscalls supported by MHD.
+ * Which threading and polling mode should be used by MHD?
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_EventLoopSyscall
+enum MHD_FIXED_ENUM_APP_SET_ MHD_WorkMode
 {
   /**
-   * Automatic selection of best-available method. This is also the
-   * default.
+   * Work mode with no internal threads.
+   * The application periodically calls #MHD_daemon_process_blocking(), where
+   * MHD internally checks all sockets automatically.
+   * This is the default mode.
    */
-  MHD_ELS_AUTO = 0
+  MHD_WM_EXTERNAL_PERIODIC = 0
   ,
   /**
-   * Use select().
+   * Work mode with an external event loop with level triggers.
+   * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered
+   * sockets polling (like select() or poll()) and #MHD_daemon_event_update().
    */
-  MHD_ELS_SELECT = 1
+  MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL = 8
   ,
   /**
-   * Use poll().
+   * Work mode with an external event loop with edge triggers.
+   * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered
+   * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update().
    */
-  MHD_ELS_POLL = 2
+  MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE = 9
   ,
   /**
-   * Use epoll.
+   * Work mode with no internal threads and aggregate watch FD.
+   * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD
+   * that gets triggered by any MHD event.
+   * This FD can be watched as an aggregate indicator for all MHD events.
+   * This mode is available only on selected platforms (currently
+   * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD.
+   * When the FD is triggered, #MHD_daemon_process_nonblocking() should
+   * be called.
    */
-  MHD_ELS_EPOLL = 3
-};
-
-
-/**
- * Force use of a particular event loop system call.
- *
- * @param daemon daemon to set event loop style for
- * @param els event loop syscall to use
- * @return #MHD_SC_OK on on success,
- *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
- *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
- *         #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system
- *         #MHD_SC_OPTIONS_CONFLICT
- */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_event_loop (struct MHD_Daemon *daemon,
-                       enum MHD_EventLoopSyscall els)
-MHD_FN_PAR_NONNULL_ (1);
-
-
-/**
- * Protocol strictness enforced by MHD on clients.
- * All levels have different parsing settings for the headers.
- */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_ProtocolStrictLevel
-{
-
-  /* * Basic levels * */
-  /**
-   * Sane level of protocol enforcement for production use.
-   * A balance between extra security and broader compatibility,
-   * as allowed by RFCs for HTTP servers.
-   */
-  MHD_PSL_DEFAULT = 0
+  MHD_WM_EXTERNAL_SINGLE_FD_WATCH = 16
   ,
   /**
-   * Be strict about the protocol (as opposed to as tolerant as
-   * possible), within the limits set by RFCs for HTTP servers.
-   * This level (and more strict) forbids use of bare LF as
-   * CRLF. It also rejects requests with both "Transfer-Encoding:"
-   * and "Content-Length:".
-   * It is suitable for public servers.
+   * Work mode with one or more worker threads.
+   * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS is not specified
+   * then daemon starts with single worker thread that process
+   * all connections.
+   * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS used with value more
+   * than one, then that number of worker threads and distributed
+   * processing of requests among the workers.
    */
-  MHD_PSL_STRICT = 1
+  MHD_WM_WORKER_THREADS = 24
   ,
   /**
-   * Be particularly permissive about the protocol, within
-   * the limits set by RFCs for HTTP servers.
+   * Work mode with one internal thread for listening and additional threads
+   * per every connection.  Use this if handling requests is CPU-intensive or
+   * blocking, your application is thread-safe and you have plenty of
+   * memory (per connection).
    */
-  MHD_PSL_PERMISSIVE = -1,
+  MHD_WM_THREAD_PER_CONNECTION = 32
+};
 
-  /* * Special levels * */
+/**
+ * Work mode parameters for #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL and
+ * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE modes
+ */
+struct MHD_WorkModeExternalEventLoopCBParam
+{
   /**
-   * Stricter protocol interpretation, even stricter then allowed
-   * by RFCs for HTTP servers.
-   * However it should be absolutely compatible with clients
-   * following at least RFCs' "MUST" type of requirements
-   * for HTTP clients.
-   * For chunked encoding parsing this level (and more strict)
-   * forbids whitespace in chunk extension.
-   * For cookies parsing this (and more strict) level rejects
-   * cookie in full even if a single value is encoded incorrectly
-   * in it.
-   * This level is recommended for testing clients against
-   * MHD. Also can be used for security-centric application,
-   * however it is slight violation of RFCs' requirements.
+   * Socket registration callback
    */
-  MHD_PSL_VERY_STRICT = 2
-  ,
+  MHD_SocketRegistrationUpdateCallback reg_cb;
   /**
-   * The most strict interpretation of the HTTP protocol,
-   * much stricter that defined for HTTP servers by RFC.
-   * However it should be absolutely compatible with clients
-   * following RFCs' "SHOULD" and "MUST" types of requirements
-   * for HTTP clients.
-   * This level can be used for testing clients against MHD.
-   * It is not recommended for any public services as it may
-   * reject legitimate clients (clients not following "SHOULD"
-   * type of RFC requirements).
+   * Closure for the @a reg_cb
    */
-  MHD_PSL_EXTRA_STRICT = 3
-  ,
+  void *reg_cb_cls;
+}
+
+/**
+ * MHD work mode parameters
+ */
+union MHD_WorkModeParam
+{
   /**
-   * More relaxed protocol interpretation, violating RFCs'
-   * "SHOULD" type of requirements for HTTP servers.
-   * For cookies parsing this (and more permissive) level
-   * allows whitespaces in cookie values.
-   * This level can be used in isolated environments.
+   * Work mode parameters for #MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL and
+   * #MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE modes
    */
-  MHD_PSL_VERY_PERMISSIVE = -2,
-
+  MHD_SocketRegistrationUpdateCallback v_external_event_loop_cb;
   /**
-   * The most flexible protocol interpretation, beyond
-   * RFCs' "MUST" type of requirements for HTTP server.
-   * The level allow HTTP/1.1 requests without "Host:" header.
-   * For cookies parsing this level adds allowance of
-   * whitespaces before and after '=' character.
-   * This level is not recommended unless it is absolutely
-   * necessary to communicate with some client(s) with
-   * badly broken HTTP implementation.
+   * Number of worker threads for #MHD_WM_WORKER_THREADS.
+   * If set to one, then daemon starts with single worker thread that process
+   * all connections.
+   * If set to value larger than one, then that number of worker threads
+   * and distributed handling of requests among the workers.
+   * Zero is treated as one.
    */
-  MHD_PSL_EXTRA_PERMISSIVE = -3,
+  unsigned int num_worker_threads;
 };
 
 /**
- * The way Strict Level is enforced.
- * MHD can be compiled with limited set of strictness levels.
- * These values instructs MHD how to apply the request level.
+ * Parameter for #MHD_DAEMON_OPTION_WORK_MODE().
+ * Not recommended to be used directly, better use macro/functions to create it:
+ * #MHD_WM_OPTION_EXTERNAL_PERIODIC(),
+ * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(),
+ * #MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(),
+ * #MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(),
+ * #MHD_WM_OPTION_WORKER_THREADS(),
+ * #MHD_WM_OPTION_THREAD_PER_CONNECTION()
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_UseStictLevel
+struct MHD_WorkModeWithParam
 {
   /**
-   * Use requested level if available or the nearest stricter
-   * level.
-   * Fail if only more permissive levels available.
-   */
-  MHD_USL_THIS_OR_STRICTER = 0
-  ,
-  /**
-   * Use requested level only.
-   * Fail if this level is not available.
+   * The work mode for MHD
    */
-  MHD_USL_PRECISE = 1
-  ,
+  enum MHD_WorkMode mode;
   /**
-   * Use requested level if available or the nearest level (stricter
-   * or more permissive).
+   * The parameters used for specified work mode
    */
-  MHD_USL_NEAREST = 2
+  union MHD_WorkModeParam params;
 };
 
+
+
+#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT)
 /**
- * Set how strictly MHD will enforce the HTTP protocol.
- *
- * @param[in,out] daemon daemon to configure strictness for
- * @param sl the level of strictness
- * @param how the way how to use the requested level
- * @return #MHD_SC_OK on on success,
- *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
- *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
- */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_protocol_strict_level (struct MHD_Daemon *daemon,
-                                  enum MHD_ProtocolStrictLevel sl,
-                                  enum MHD_UseStictLevel how)
-MHD_FN_PAR_NONNULL_ (1);
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * no internal threads.
+ * The application periodically calls #MHD_daemon_process_blocking(), where
+ * MHD internally checks all sockets automatically.
+ * This is the default mode.
+ * @return the object of struct MHD_WorkModeWithParam with requested values
+ */
+#  define MHD_WM_OPTION_EXTERNAL_PERIODIC()     \
+  MHD_NOWARN_COMPOUND_LITERALS_                 \
+  (const struct MHD_WorkModeWithParam)          \
+  {                                             \
+    .mode = (MHD_WM_EXTERNAL_PERIODIC)          \
+  }                                             \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
 
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_option_string (struct MHD_Daemon *daemon,
-                              enum foo,
-                              const char *value)
-MHD_FN_PAR_NONNULL_ (1);
+/**
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * an external event loop with level triggers.
+ * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered
+ * sockets polling (like select() or poll()) and #MHD_daemon_event_update().
+ * @param cb_val the callback for sockets registration
+ * @param cb_cls_val the closure for the @a cv_val callback
+ * @return the object of struct MHD_WorkModeWithParam with requested values
+ */
+#  define MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(cb_val,cb_cls_val) \
+  MHD_NOWARN_COMPOUND_LITERALS_                                         \
+  (const struct MHD_WorkModeWithParam)                                  \
+  {                                                                     \
+    .mode = (MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL),                      \
+    .params.v_external_event_loop_cb.reg_cb = (cb_val),                 \
+    .params.v_external_event_loop_cb.reg_cb_cls = (cb_cls_val)          \
+  }                                                                     \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
 
 /**
- * Provide TLS key and certificate data in-memory.
- *
- * @param daemon which instance should be configured
- * @param mem_key private key (key.pem) to be used by the
- *     HTTPS daemon.  Must be the actual data in-memory, not a filename.
- * @param mem_cert certificate (cert.pem) to be used by the
- *     HTTPS daemon.  Must be the actual data in-memory, not a filename.
- * @param pass passphrase phrase to decrypt 'key.pem', NULL
- *     if @param mem_key is in cleartext already
- * @return #MHD_SC_OK upon success;
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * an external event loop with edge triggers.
+ * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered
+ * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update().
+ * @param cb_val the callback for sockets registration
+ * @param cb_cls_val the closure for the @a cv_val callback
+ * @return the object of struct MHD_WorkModeWithParam with requested values
+ */
+#  define MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(cb_val,cb_cls_val)  \
+  MHD_NOWARN_COMPOUND_LITERALS_                                         \
+  (const struct MHD_WorkModeWithParam)                                  \
+  {                                                                     \
+    .mode = (MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE),                       \
+    .params.v_external_event_loop_cb.reg_cb = (cb_val),                 \
+    .params.v_external_event_loop_cb.reg_cb_cls = (cb_cls_val)          \
+  }                                                                     \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+
+/**
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * no internal threads and aggregate watch FD.
+ * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD
+ * that gets triggered by any MHD event.
+ * This FD can be watched as an aggregate indicator for all MHD events.
+ * This mode is available only on selected platforms (currently
+ * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD.
+ * When the FD is triggered, #MHD_daemon_process_nonblocking() should
+ * be called.
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon,
-                                         const char *mem_key,
-                                         const char *mem_cert,
-                                         const char *pass)
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
-MHD_FN_PAR_NONNULL_ (3);
+#  define MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH()      \
+  MHD_NOWARN_COMPOUND_LITERALS_                         \
+  (const struct MHD_WorkModeWithParam)                  \
+  {                                                     \
+    .mode = (MHD_WM_EXTERNAL_SINGLE_FD_WATCH)           \
+  }                                                     \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
 
+/**
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * one or more worker threads.
+ * If number of threads is one, then daemon starts with single worker thread
+ * that handles all connections.
+ * If number of threads is larger than one, then that number of worker threads,
+ * and handling of connection is distributed among the workers.
+ * @param num_workers the number of worker threads, zero is treated as one
+ * @return the object of struct MHD_WorkModeWithParam with requested values
+ */
+#  define MHD_WM_OPTION_WORKER_THREADS(num_workers)     \
+  MHD_NOWARN_COMPOUND_LITERALS_                         \
+  (const struct MHD_WorkModeWithParam)                  \
+  {                                                     \
+    .mode = (MHD_WM_WORKER_THREADS),                    \
+    .params.num_worker_threads = (num_workers)          \
+  }                                                     \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
 
 /**
- * Configure DH parameters (dh.pem) to use for the TLS key
- * exchange.
- *
- * @param daemon daemon to configure tls for
- * @param dh parameters to use
- * @return #MHD_SC_OK upon success; TODO: define failure modes
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * one internal thread for listening and additional threads per every
+ * connection.  Use this if handling requests is CPU-intensive or blocking,
+ * your application is thread-safe and you have plenty of memory (per
+ * connection).
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon,
-                             const char *dh)
-MHD_FN_PAR_NONNULL_ (1);
+#  define MHD_WM_OPTION_THREAD_PER_CONNECTION() \
+  MHD_NOWARN_COMPOUND_LITERALS_                 \
+  (const struct MHD_WorkModeWithParam)          \
+  {                                             \
+    .mode = (MHD_WM_THREAD_PER_CONNECTION)      \
+  }                                             \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+
+#else  /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */
+MHD_NOWARN_UNUSED_FUNC_
 
 /**
- * Memory pointer for the certificate (ca.pem) to be used by the
- * HTTPS daemon for client authentication.
- *
- * @param daemon daemon to configure tls for
- * @param mem_trust memory pointer to the certificate
- * @return #MHD_SC_OK upon success; TODO: define failure modes
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * no internal threads.
+ * The application periodically calls #MHD_daemon_process_blocking(), where
+ * MHD internally checks all sockets automatically.
+ * This is the default mode.
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_tls_mem_trust (struct MHD_Daemon *daemon,
-                          const char *mem_trust)
-MHD_FN_PAR_NONNULL_ (1);
+static MHD_INLINE struct MHD_WorkModeWithParam
+MHD_WM_OPTION_EXTERNAL_PERIODIC(void)
+{
+  struct MHD_WorkModeWithParam wm_val;
 
+  wm_val.mode = MHD_WM_EXTERNAL_PERIODIC;
 
-/* ********************** (d) TLS support ********************** */
+  return wm_val;
+}
 
 /**
- * The TLS backend choice
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * an external event loop with level triggers.
+ * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered
+ * sockets polling (like select() or poll()) and #MHD_daemon_event_update().
+ * @param cb_val the callback for sockets registration
+ * @param cb_cls_val the closure for the @a cv_val callback
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
+static MHD_INLINE struct MHD_WorkModeWithParam
+MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL(
+    MHD_SocketRegistrationUpdateCallback cb_val,
+    void *cb_cls_val)
 {
-  /**
-   * Disable TLS, use plain TCP connections
-   */
-  MHD_TLS_BACKEND_NONE = 0
-  ,
-  /**
-   * Use best available TLS backend.
-   * Currently this is equivalent to GnuTLS (if TLS is enabled
-   * for MHD build).
-   */
-  MHD_TLS_BACKEND_ANY = 1
-  ,
-  /**
-   * Use GnuTLS as TLS backend.
-   */
-  MHD_TLS_BACKEND_GNUTLS = 2
-};
+  struct MHD_WorkModeWithParam wm_val;
+
+  wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL;
+  wm_val.params.v_external_event_loop_cb.reg_cb = cb_val;
+  wm_val.params.v_external_event_loop_cb.reg_cb_cls = cb_cls_val;
+
+  return wm_val;
+}
 
 /**
- * Values for #MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE.
- *
- * These values can limit the scope of validity of MHD-generated nonces.
- * Values can be combined with bitwise OR.
- * Any value, except #MHD_DAUTH_BIND_NONCE_NONE, enforce function
- * #MHD_digest_auth_check() (and similar functions) to check nonce by
- * re-generating it again with the same parameters, which is CPU-intensive
- * operation.
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * an external event loop with edge triggers.
+ * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered
+ * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update().
+ * @param cb_val the callback for sockets registration
+ * @param cb_cls_val the closure for the @a cv_val callback
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-enum MHD_FIXED_FLAGS_ENUM_APP_SET_ MHD_DaemonOptionValueDAuthBindNonce
+static MHD_INLINE struct MHD_WorkModeWithParam
+MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE(
+    MHD_SocketRegistrationUpdateCallback cb_val,
+    void *cb_cls_val)
 {
-  /**
-   * Generated nonces are valid for any request from any client until expired.
-   * This is default and recommended value.
-   * #MHD_digest_auth_check3() (and similar functions) would check only whether
-   * the nonce value that is used by client has been generated by MHD and not
-   * expired yet.
-   * It is recommended because RFC 7616 allows clients to use the same nonce
-   * for any request in the same "protection space".
-   * When checking client's authorisation requests CPU is loaded less if this
-   * value is used.
-   * This mode gives MHD maximum flexibility for nonces generation and can
-   * prevent possible nonce collisions (and corresponding log warning messages)
-   * when clients' requests are intensive.
-   * This value cannot be biwise-OR combined with other values.
-   */
-  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE = 0,
+  struct MHD_WorkModeWithParam wm_val;
 
-  /**
-   * Generated nonces are valid only for the same realm.
-   */
-  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_REALM = 1 << 0,
+  wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE;
+  wm_val.params.v_external_event_loop_cb.reg_cb = cb_val;
+  wm_val.params.v_external_event_loop_cb.reg_cb_cls = cb_cls_val;
 
-  /**
-   * Generated nonces are valid only for the same URI (excluding parameters
-   * after '?' in URI) and request method (GET, POST etc).
-   * Not recommended unless "protection space" is limited to a single URI as
-   * RFC 7616 allows clients to re-use server-generated nonces for any URI
-   * in the same "protection space" which by default consists of all server
-   * URIs.
-   * Before #MHD_VERSION 0x00097701 this was default (and only supported)
-   * nonce bind type.
-   */
-  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_URI = 1 << 1,
+  return wm_val;
+}
 
-  /**
-   * Generated nonces are valid only for the same URI including URI parameters
-   * and request method (GET, POST etc).
-   * This value implies #MHD_DAUTH_BIND_NONCE_URI.
-   * Not recommended for that same reasons as #MHD_DAUTH_BIND_NONCE_URI.
-   */
-  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_URI_PARAMS = 1 << 2,
+/**
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * no internal threads and aggregate watch FD.
+ * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD
+ * that gets triggered by any MHD event.
+ * This FD can be watched as an aggregate indicator for all MHD events.
+ * This mode is available only on selected platforms (currently
+ * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD.
+ * When the FD is triggered, #MHD_daemon_process_nonblocking() should
+ * be called.
+ * @return the object of struct MHD_WorkModeWithParam with requested values
+ */
+static MHD_INLINE struct MHD_WorkModeWithParam
+MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH(void)
+{
+  struct MHD_WorkModeWithParam wm_val;
 
-  /**
-   * Generated nonces are valid only for the single client's IP.
-   * While it looks like security improvement, in practice the same client may
-   * jump from one IP to another (mobile or Wi-Fi handover, DHCP re-assignment,
-   * Multi-NAT, different proxy chain and other reasons), while IP address
-   * spoofing could be used relatively easily.
-   */
-  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_CLIENT_IP = 1 << 3
-};
+  wm_val.mode = MHD_WM_EXTERNAL_SINGLE_FD_WATCH;
+
+  return wm_val;
+}
 
 /**
- * Enable and configure TLS.
- *
- * @param daemon which instance should be configured
- * @param tls_backend which TLS backend should be used,
- *    currently only "gnutls" is supported.  You can
- *    also specify NULL for best-available (which is the default).
- * @return status code, #MHD_SC_OK upon success
- *     #MHD_TLS_BACKEND_UNSUPPORTED if the @a backend is unknown
- *     #MHD_TLS_DISABLED if this build of MHD does not support TLS
- *     #MHD_TLS_CIPHERS_INVALID if the given @a ciphers are not supported
- *     by this backend
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * one or more worker threads.
+ * If number of threads is one, then daemon starts with single worker thread
+ * that handles all connections.
+ * If number of threads is larger than one, then that number of worker threads,
+ * and handling of connection is distributed among the workers.
+ * @param num_workers the number of worker threads, zero is treated as one
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_tls_backend (struct MHD_Daemon *daemon,
-                            enum MHD_TlsBackend backend)
-MHD_FN_PAR_NONNULL_ (1);
+static MHD_INLINE struct MHD_WorkModeWithParam
+MHD_WM_OPTION_WORKER_THREADS(unsigned int num_workers)
+{
+  struct MHD_WorkModeWithParam wm_val;
 
+  wm_val.mode = MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE;
+  wm_val.params.num_worker_threads = num_workers;
+
+  return wm_val;
+}
 
 /**
- * Context required to provide a pre-shared key to the
- * server.
- *
- * @param ...
- * @param psk_size the number of bytes in @a psk
- * @param psk the pre-shared-key; should be allocated with malloc(),
- *                 will be freed by MHD
+ * Create parameter for #MHD_DAEMON_OPTION_WORK_MODE() for work mode with
+ * one internal thread for listening and additional threads per every
+ * connection.  Use this if handling requests is CPU-intensive or blocking,
+ * your application is thread-safe and you have plenty of memory (per
+ * connection).
+ * @return the object of struct MHD_WorkModeWithParam with requested values
  */
-struct MHD_ServerCredentialsContext;
+static MHD_INLINE struct MHD_WorkModeWithParam
+MHD_WM_OPTION_THREAD_PER_CONNECTION(void)
+{
+  struct MHD_WorkModeWithParam wm_val;
 
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_connection_set_psk (struct MHD_ServerCredentialsContext *mscc,
-                        size_t psk_size,
-                        const /*void? */ char psk[MHD_C99_ (psk_size)]);
+  wm_val.mode = MHD_WM_THREAD_PER_CONNECTION;
 
-#define MHD_connection_set_psk_unavailable(mscc) \
-  MHD_connection_set_psk (mscc, 0, NULL)
+  return wm_val;
+}
+
+MHD_RESTORE_WARN_UNUSED_FUNC_
+#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */
 
 
 /**
- * Function called to lookup the pre-shared key (PSK) for a given
- * HTTP connection based on the @a username.  MHD will suspend handling of
- * the @a connection until the application calls #MHD_connection_set_psk().
- * If looking up the PSK fails, the application must still call
- * #MHD_connection_set_psk_unavailable().
+ * Specify threading mode to use.
+ *
+ * @param[in,out] daemon daemon to configure
+ * @param tm mode to use
+ */
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_threading_mode (struct MHD_Daemon *daemon,
+                               enum MHD_ThreadingMode tm)
+MHD_FN_PAR_NONNULL_ (1);
+
+/**
+ * Type of a callback function used for logging by MHD.
  *
  * @param cls closure
- * @param connection the HTTPS connection
- * @param username the user name claimed by the other side
- * @param mscc context to pass to #MHD_connection_set_psk().
- * @return 0 on success, -1 on errors
+ * @param sc status code of the event
+ * @param fm format string (`printf()`-style)
+ * @param ap arguments to @a fm
+ * @ingroup logging
  */
 typedef void
-(*MHD_PskServerCredentialsCallback)(void *cls,
-                                    const struct MHD_Connection *connection,
-                                    const struct MHD_String *username,
-                                    struct MHD_ServerCredentialsContext *mscc);
-
+(MHD_FN_PAR_NONNULL_(3)
+ MHD_FN_PAR_CSTR_(3)
+ *MHD_LoggingCallback)(void *cls,
+                       enum MHD_StatusCode sc,
+                       const char *fm,
+                       va_list ap);
 
+// FIXME: convert
 /**
- * Configure PSK to use for the TLS key exchange.
+ * Convenience macro used to disable logging.
  *
- * @param daemon daemon to configure tls for
- * @param psk_cb function to call to obtain pre-shared key
- * @param psk_cb_cls closure for @a psk_cb
- * @return #MHD_SC_OK upon success; TODO: define failure modes
+ * @param daemon which instance to disable logging for
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_tls_psk_callback (struct MHD_Daemon *daemon,
-                                 MHD_PskServerCredentialsCallback psk_cb,
-                                 void *psk_cb_cls)
-MHD_FN_PAR_NONNULL_ (1);
+#define MHD_daemon_disable_logging(daemon) \
+  MHD_daemon_set_logger ((daemon), \
+                         MHD_STATIC_CAST_(MHD_LoggingCallback,NULL),   \
+                         NULL)
 
+/**
+ * Parameter for listen socket binding type
+ */
+enum MHD_FIXED_ENUM_APP_SET_ MHD_DaemonOptionBindType
+{
+  /**
+   * The listen socket bind to the networks address without sharing the address.
+   * Default.
+   */
+  MHD_DAEMON_OPTION_BIND_TYPE_NOT_SHARED = 0
+  ,
+  /**
+   * The listen socket bind to the networks address with sharing the address.
+   * Several sockets can bind to the same address.
+   */
+  MHD_DAEMON_OPTION_BIND_TYPE_SHARED = 1
+  ,
+  /**
+   * The list socket bind to the networks address in explicit exclusive mode.
+   * Ignored on platforms without support for the explicit exclusive socket use.
+   */
+  MHD_DAEMON_OPTION_BIND_TYPE_EXCLUSIVE = 2
+};
 
 
-// Callback invoked between full initialization of MHD
-// during MHD_daemon_start() and actual event loop
-// starting to accept incoming connections. So at this
-// point, the listen socket (and if applicable TLS context)
-// will be available for introspection.
-typedef void
-(*MHD_DaemonReadyCallback)(void *cls);
-
+enum MHD_FIXED_ENUM_APP_SET_ MHD_DaemonOption
+{
+  /**
+   * Not a real option.
+   * Should not be used directly.
+   * This value indicates the end of the list of the options.
+   */
+  MHD_D_O_END = 0
+  ,
+  /**
+   * Suppresses use of "Date:" header.
+   * According to RFC should be used only if the system has no RTC.
+   * The "Date:" is not suppressed (the header is enabled) by default.
+   */
+  MHD_D_O_BOOL_SUPPRESS_DATE_HEADER = 100
+  ,
+  /**
+   * Enable `turbo`.  Disables certain calls to `shutdown()`,
+   * enables aggressive non-blocking optimistic reads and
+   * other potentially unsafe optimisations.
+   * Most effects only happen with internal threads with epoll.
+   * The 'turbo' mode is not enabled (mode is disabled) by default.
+   */
+  MHD_D_O_BOOL_TURBO = 102
+  ,
+  /**
+   * Disable some internal thread safety.
+   * Indicates that MHD daemon will be used by application in single-threaded
+   * mode only.  When this flag is set then application must call any MHD
+   * function only within a single thread.
+   * This flag turns off some internal thread-safety and allows MHD making
+   * some of the internal optimisations suitable only for single-threaded
+   * environment.
+   * Not compatible with any internal threads mode.
+   * Thread safety is not disabled (safety is enabled) by default.
+   */
+  MHD_D_O_DISABLE_THREAD_SAFETY = 103
+  ,
+  /**
+   * You need to set this option if you want to disable use of HTTP "Upgrade".
+   * "Upgrade" may require usage of additional internal resources,
+   * which we can avoid providing if they will not be used.
+   *
+   * You should only use this function if you do not use "Upgrade" functionality
+   * and need a generally minor boost in performance.
+   * The "Upgrade" is not disallowed ("upgrade" is allowed) by default.
+   */
+  MHD_D_O_BOOL_DISALLOW_UPGRADE = 104
+  ,
+  /**
+   * Disable #MHD_action_suspend() functionality.
+   *
+   * You should only use this function if you do not use suspend functionality
+   * and need a generally minor boost in performance.
+   * The suspend is not disallowed (suspend is allowed) by default.
+   */
+  MHD_D_O_BOOL_DISALLOW_SUSPEND_RESUME
+  ,
+  /**
+   * Use SHOUTcast.  This will cause *all* responses to begin
+   * with the SHOUTcast "ICY" line instead of "HTTP".
+   */
+  MHD_D_O_BOOL_ENABLE_SHOUTCAST
+  ,
+  /**
+   * Disable converting plus ('+') character to space in GET
+   * parameters (URI part after '?').
+   * TODO: Add explanation, RFCs, HTML
+   */
+  MHD_D_O_BOOL_DISABLE_GET_PARAM_PLUS_AS_SPACE,
 
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_daemon_ready_callback (struct MHD_Daemon *daemon,
-                                      MHD_DaemonReadyCallback cb,
-                                      void *cb)
-MHD_FN_PAR_NONNULL_ (1);
+  /**
+   * Bind to the given socket address.
+   */
+  MHD_D_O_SA
+  ,
+  /**
+   * If present true, allow reusing address:port socket (by using
+   * SO_REUSEPORT on most platform, or platform-specific ways).  If
+   * present and set to false, disallow reusing address:port socket
+   * (does nothing on most platform, but uses SO_EXCLUSIVEADDRUSE on
+   * Windows).
+   * Ineffective in conjunction with #MHD_daemon_listen_socket().
+   */
+  MHD_D_O_BOOL_LISTEN_ALLOW_ADDRESS_REUSE
+};
 
+// FIXME: transform everything to option
 
 /**
- * Allow or deny a client to connect.
- *
- * @param cls closure
- * @param addrlen length of @a addr
- * @param addr address information from the client
- * @see #MHD_daemon_accept_policy()
- * @return #MHD_YES if connection is allowed, #MHD_NO if not
+ * Possible levels of enforcement for TCP_FASTOPEN.
  */
-typedef enum MHD_Bool
-(*MHD_AcceptPolicyCallback)(void *cls,
-                            size_t addr_len,
-                            const struct sockaddr *addr);
-
+enum MHD_FIXED_ENUM_APP_SET_ MHD_TCPFastOpenType
+{
+  /**
+   * Disable use of TCP_FASTOPEN.
+   */
+  MHD_FOM_DISABLE = -1
+  ,
+  /**
+   * Enable TCP_FASTOPEN where supported.
+   * On GNU/Linux it works with a kernel >= 3.6.
+   * This is the default.
+   */
+  MHD_FOM_AUTO = 0
+  ,
+  /**
+   * Require TCP_FASTOPEN.
+   * Also causes #MHD_daemon_start() to fail if setting
+   * the option fails later.
+   */
+  MHD_FOM_REQUIRE = 1
+};
 
-/**
- * Set a policy callback that accepts/rejects connections
- * based on the client's IP address.  This function will be called
- * before a connection object is created.
- *
- * @param daemon daemon to set policy for
- * @param apc function to call to check the policy
- * @param apc_cls closure for @a apc
- */
-MHD_EXTERN_ void
-MHD_daemon_accept_policy (struct MHD_Daemon *daemon,
-                          MHD_AcceptPolicyCallback apc,
-                          void *apc_cls)
-MHD_FN_PAR_NONNULL_ (1);
 
 
 /**
- * Function called by MHD to allow the application to log
- * the @a full_uri of a @a request.
- * This is the only moment when unmodified URI is provided.
- * After this callback MHD parses the URI and modifies it
- * by extracting GET parameters in-place.
- *
- * @param cls client-defined closure
- * @param[in,out] request the HTTP request handle (headers are
- *         not yet available)
- * @param uri the full URI from the HTTP request including parameters (after '?')
+ * Address family to be used by MHD.
  */
-typedef void
-(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
- *MHD_EarlyUriLogCallback)(void *cls,
-                           struct MHD_Request *request,
-                           const struct MHD_String *full_uri);
+enum MHD_FIXED_ENUM_APP_SET_ MHD_AddressFamily
+{
+  /**
+   * Option not given, do not listen at all
+   * (unless listen socket or address specified by
+   * other means).
+   */
+  MHD_AF_NONE = 0
+  ,
+  /**
+   * Pick "best" available method automatically.
+   */
+  MHD_AF_AUTO = 1
+  ,
+  /**
+   * Use IPv4.
+   */
+  MHD_AF_INET4 = 2
+  ,
+  /**
+   * Use IPv6.
+   */
+  MHD_AF_INET6 = 3
+  ,
+  /**
+   * Use dual stack.
+   */
+  MHD_AF_DUAL = 4
+};
 
 
 /**
- * Register a callback to be called first for every request
- * (before any parsing of the header).  Makes it easy to
- * log the full URL.
+ * Bind to the given socket address.
+ * Ineffective in conjunction with #MHD_daemon_listen_socket().
  *
- * @param daemon daemon for which to set the logger
- * @param cb function to call
- * @param cb_cls closure for @a cb
+ * @param[in,out] daemon which instance to configure the binding address for
+ * @param sa address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6)
+ *        or even a UNIX domain socket (AF_UNIX)
+ * @param sa_len number of bytes in @a sa
+ * @return #MHD_SC_OK on on success,
+ *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
+ *         #MHD_SC_FEATURE_DISABLED,
+ *         #MHD_SC_FEATURE_NOT_AVAILABLE,
+ *         #MHD_SC_OPTIONS_CONFLICT
  */
 MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_early_uri_logger (struct MHD_Daemon *daemon,
-                                 MHD_EarlyUriLogCallback cb,
-                                 void *cb_cls)
-MHD_FN_PAR_NONNULL_ (1);
-
+MHD_daemon_bind_socket_address (struct MHD_Daemon *daemon,
+                                const struct sockaddr *sa,
+                                size_t sa_len)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
 
-/**
- * The `enum MHD_ConnectionNotificationCode` specifies types
- * of connection notifications.
- * @ingroup request
- */
-enum MHD_FIXED_ENUM_MHD_SET_ MHD_ConnectionNotificationCode
+// TODO: Sort values and assign numbers
+enum MHD_DeamonOptionUInt
 {
+  /**
+   * Use the given backlog for the listen() call.
+   * Ineffective in conjunction with #MHD_daemon_listen_socket()
+   */
+  MHD_DAEMON_OPTION_UINT_LISTEN_BACKLOG,
+  /**
+   * Maximum number of (concurrent) network connections served
+   * by daemon
+   */
+  MHD_DAEMON_OPTION_UINT_GLOBAL_CONNECTION_LIMIT,
+  /**
+   * Limit on the number of (concurrent) network connections
+   * made to the server from the same IP address.
+   * Can be used to prevent one IP from taking over all of
+   * the allowed connections. If the same IP tries to establish
+   * more than the specified number of connections, they will
+   * be immediately rejected.
+   */
+  MHD_DAEMON_OPTION_UINT_IP_CONNECTION_LIMIT,
 
   /**
-   * A new connection has been started.
-   * @ingroup request
+   * After how many seconds of inactivity should a
+   * connection automatically be timed out?
+   * Use zero for no timeout, which is also the (unsafe!) default.
    */
-  MHD_CONNECTION_NOTIFY_STARTED = 0
-  ,
+  MHD_DAEMON_OPTION_UINT_DEFAULT_TIMEOUT,
+
   /**
-   * A connection is closed.
-   * @ingroup request
+   * The number of worker threads.
+   * Only useful if the selected threading mode
+   * is #MHD_TM_WORKER_THREADS.
+   * Zero number is silently ignored.
    */
-  MHD_CONNECTION_NOTIFY_CLOSED = 1
+  MHD_DAEMON_OPTION_UINT_NUM_WORKERS
 
 };
 
 /**
- * Extra details for connection notifications.
- * Currently not used
+ * Set unsigned integer MHD option.
+ *
+ * @param[in,out] daemon which instance to set uint @a option for
+ * @param option option to modify
+ * @param value new value for the option
+ * @return #MHD_SC_OK on on success,
+ *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
+ *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
+ *         #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system
+ *         #MHD_SC_OPTIONS_CONFLICT
  */
-union MHD_ConnectionNotificationDetails
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_option_uint (struct MHD_Daemon *daemon,
+                            enum MHD_DeamonOptionUInt option,
+                            unsigned int value)
+MHD_FN_PAR_NONNULL_ (1);
+
+// FIXME: Alternative or additional implementation.
+
+struct MHD_DaemonOptioniUIntEntry
 {
   /**
-   * Unused
+   * The option to update the @a value
    */
-  int reserved1;
+  enum MHD_DeamonOptionUInt option;
+  /**
+   * The value to update for the @a option
+   */
+  unsigned int value;
+  // TODO: union
 };
 
+#if 0
+/**
+ * Set unsigned integer MHD options.
+ *
+ * @param[in,out] daemon which instance to set uint @a option for
+ * @param num_entries the number of entries in the @a opt_val array
+ *                    and in @a results (if not NULL)
+ * @param[in] opt_val the array with options and values to modify
+ * @param[out] results the results for the applying the options,
+ *                     can be NULL,
+ *                     if not NULL must have @a num_entries entries
+ * @return #MHD_YES if all options have applied successfully
+ *         #MHD_NO if at least single option failed (for more
+ *         details check @a results)
+ */
+MHD_EXTERN_ enum MHD_StatusCode // First failed // TODO: Document that rest may be used
+MHD_daemon_set_option_uint (
+  struct MHD_Daemon *daemon,
+  size_t num_entries,
+  struct MHD_DaemonOptioniUIntEntry opt_val[MHD_C99_ (static num_entries)])
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3);
+#endif
+// TODO: combine all types of options into single list with union
+/**
+ * Accept connections from the given socket.  Socket
+ * must be a TCP or UNIX domain (stream) socket.
+ *
+ * Unless MHD_INVALID_SOCKET is given, this disables
+ * other listen options.
+ *
+ * @param daemon daemon to set listen socket for
+ * @param listen_socket listen socket to use,
+ *        MHD_INVALID_SOCKET value will cause this call to be
+ *        ignored (other binding options may still be effective)
+ * @return #MHD_SC_OK on on success,
+ *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
+ *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
+ *         #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system
+ *         #MHD_SC_OPTIONS_CONFLICT
+ */
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_listen_socket (struct MHD_Daemon *daemon,
+                          MHD_socket listen_socket)
+MHD_FN_PAR_NONNULL_ (1);
 
 /**
- * The connection notification data structure
+ * Sockets polling internal syscalls used by MHD.
  */
-struct MHD_ConnectionNotificationData
+enum MHD_FIXED_ENUM_APP_SET_ MHD_SockPollSyscall
 {
   /**
-   * The connection handle
+   * Automatic selection of best-available method. This is also the
+   * default.
    */
-  struct MHD_Connection *connection;
-  /**
-   * The connection-specific application context data (opaque for MHD).
-   * Initially set to NULL (for connections added by MHD) or set by
-   * @a connection_cntx parameter for connections added by
-   * #MHD_daemon_add_connection().
+  MHD_ELS_AUTO = 0
+  ,
+  /**
+   * Use select().
    */
-  void *application_context;
+  MHD_ELS_SELECT = 1
+  ,
   /**
-   * The code of the event
+   * Use poll().
    */
-  enum MHD_ConnectionNotificationCode code;
+  MHD_ELS_POLL = 2
+  ,
   /**
-   * Event details
+   * Use epoll.
    */
-  union MHD_ConnectionNotificationDetails details;
+  MHD_ELS_EPOLL = 3
 };
 
 
 /**
- * Signature of the callback used by MHD to notify the
- * application about started/stopped network connections
- *
- * @param cls client-defined closure
- * @param[in,out]  data the details about the event
- * @see #MHD_daemon_set_notify_connection()
- * @ingroup request
- */
-typedef void
-(MHD_FN_PAR_NONNULL_ (2)
- *MHD_NotifyConnectionCallback)(void *cls,
-                                struct MHD_ConnectionNotificationData *data);
-
-
-/**
- * Register a function that should be called whenever a connection is
- * started or closed.
+ * Force use of a particular event loop system call.
  *
- * @param daemon daemon to set callback for
- * @param ncc function to call to check the policy
- * @param ncc_cls closure for @a apc
+ * @param daemon daemon to set event loop style for
+ * @param els event loop syscall to use
+ * @return #MHD_SC_OK on on success,
+ *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
+ *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
+ *         #MHD_SC_FEATURE_NOT_AVAILABLE if this options is not supported on this system
+ *         #MHD_SC_OPTIONS_CONFLICT
  */
 MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_notify_connection (struct MHD_Daemon *daemon,
-                                  MHD_NotifyConnectionCallback ncc,
-                                  void *ncc_cls)
+MHD_daemon_event_loop (struct MHD_Daemon *daemon,
+                       enum MHD_EventLoopSyscall els)
 MHD_FN_PAR_NONNULL_ (1);
 
 
 /**
- * The type of stream notifications.
- * @ingroup request
+ * Protocol strictness enforced by MHD on clients.
+ * All levels have different parsing settings for the headers.
  */
-enum MHD_FIXED_ENUM_MHD_SET_ MHD_StreamNotificationCode
+enum MHD_FIXED_ENUM_APP_SET_ MHD_ProtocolStrictLevel
 {
+
+  /* * Basic levels * */
   /**
-   * A new connection has been started.
-   * @ingroup request
+   * Sane level of protocol enforcement for production use.
+   * A balance between extra security and broader compatibility,
+   * as allowed by RFCs for HTTP servers.
    */
-  MHD_STREAM_NOTIFY_STARTED = 0
+  MHD_PSL_DEFAULT = 0
   ,
   /**
-   * A connection is closed.
-   * @ingroup request
+   * Be strict about the protocol (as opposed to as tolerant as
+   * possible), within the limits set by RFCs for HTTP servers.
+   * This level (and more strict) forbids use of bare LF as
+   * CRLF. It also rejects requests with both "Transfer-Encoding:"
+   * and "Content-Length:".
+   * It is suitable for public servers.
    */
-  MHD_STREAM_NOTIFY_CLOSED = 1
-
-};
+  MHD_PSL_STRICT = 1
+  ,
+  /**
+   * Be particularly permissive about the protocol, within
+   * the limits set by RFCs for HTTP servers.
+   */
+  MHD_PSL_PERMISSIVE = -1,
 
-/**
- * Additional information about stream started event
- */
-struct MHD_StreamNotificationDetailStarted
-{
+  /* * Special levels * */
   /**
-   * Set to #MHD_YES of the stream was started by client
+   * Stricter protocol interpretation, even stricter then allowed
+   * by RFCs for HTTP servers.
+   * However it should be absolutely compatible with clients
+   * following at least RFCs' "MUST" type of requirements
+   * for HTTP clients.
+   * For chunked encoding parsing this level (and more strict)
+   * forbids whitespace in chunk extension.
+   * For cookies parsing this (and more strict) level rejects
+   * cookie in full even if a single value is encoded incorrectly
+   * in it.
+   * This level is recommended for testing clients against
+   * MHD. Also can be used for security-centric application,
+   * however it is slight violation of RFCs' requirements.
    */
-  enum MHD_Bool by_client;
-};
+  MHD_PSL_VERY_STRICT = 2
+  ,
+  /**
+   * The most strict interpretation of the HTTP protocol,
+   * much stricter that defined for HTTP servers by RFC.
+   * However it should be absolutely compatible with clients
+   * following RFCs' "SHOULD" and "MUST" types of requirements
+   * for HTTP clients.
+   * This level can be used for testing clients against MHD.
+   * It is not recommended for any public services as it may
+   * reject legitimate clients (clients not following "SHOULD"
+   * type of RFC requirements).
+   */
+  MHD_PSL_EXTRA_STRICT = 3
+  ,
+  /**
+   * More relaxed protocol interpretation, violating RFCs'
+   * "SHOULD" type of restrictions for HTTP servers.
+   * For cookies parsing this (and more permissive) level
+   * allows whitespaces in cookie values.
+   * This level can be used in isolated environments.
+   */
+  MHD_PSL_VERY_PERMISSIVE = -2,
 
-/**
- * Additional information about stream events
- */
-union MHD_StreamNotificationDetail
-{
   /**
-   * Information for event #MHD_STREAM_NOTIFY_STARTED
+   * The most flexible protocol interpretation, beyond
+   * RFCs' "MUST" type of restrictions for HTTP server.
+   * The level allow HTTP/1.1 requests without "Host:" header.
+   * For cookies parsing this level adds allowance of
+   * whitespaces before and after '=' character.
+   * This level is not recommended unless it is absolutely
+   * necessary to communicate with some client(s) with
+   * badly broken HTTP implementation.
    */
-  struct MHD_StreamNotificationDetailStarted started;
+  MHD_PSL_EXTRA_PERMISSIVE = -3,
 };
 
 /**
- * Stream notification data structure
+ * The way Strict Level is enforced.
+ * MHD can be compiled with limited set of strictness levels.
+ * These values instructs MHD how to apply the request level.
  */
-struct MHD_StreamNotificationData
+enum MHD_FIXED_ENUM_APP_SET_ MHD_UseStictLevel
 {
   /**
-   * The handle of the stream
+   * Use requested level if available or the nearest stricter
+   * level.
+   * Fail if only more permissive levels available.
+   * Recommended value.
    */
-  struct MHD_Stream *stream;
+  MHD_USL_THIS_OR_STRICTER = 0
+  ,
   /**
-   * The code of the event
+   * Use requested level only.
+   * Fail if this level is not available.
    */
-  enum MHD_StreamNotificationCode code;
+  MHD_USL_PRECISE = 1
+  ,
   /**
-   * Detailed information about notification event
+   * Use requested level if available or the nearest level (stricter
+   * or more permissive).
    */
-  union MHD_StreamNotificationDetail details;
+  MHD_USL_NEAREST = 2
 };
 
-
 /**
- * Signature of the callback used by MHD to notify the
- * application about started/stopped data stream
- * For HTTP/1.1 it is the same like network connection
- * with 1:1 match.
+ * Set how strictly MHD will enforce the HTTP protocol.
  *
- * @param cls client-defined closure
- * @param data the details about the event
- * @see #MHD_OPTION_NOTIFY_CONNECTION
- * @ingroup request
+ * @param[in,out] daemon daemon to configure strictness for
+ * @param sl the level of strictness
+ * @param how the way how to use the requested level
+ * @return #MHD_SC_OK on on success,
+ *         #MHD_SC_TOO_LATE if this option was set after the daemon was started and it cannot be set anymore
+ *         #MHD_SC_FEATURE_DISABLED if this option is not implemented in this version of the library,
  */
-typedef void
-(MHD_FN_PAR_NONNULL_ (2)
- *MHD_NotifyStreamCallback)(
-   void *cls,
-   const struct MHD_StreamNotificationData *data);
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_protocol_strict_level (struct MHD_Daemon *daemon,
+                                  enum MHD_ProtocolStrictLevel sl,
+                                  enum MHD_UseStictLevel how)
+MHD_FN_PAR_NONNULL_ (1);
 
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_option_string (struct MHD_Daemon *daemon,
+                              enum foo,
+                              const char *value)
+MHD_FN_PAR_NONNULL_ (1);
 
 /**
- * Register a function that should be called whenever a stream is
- * started or closed.
+ * Provide TLS key and certificate data in-memory.
  *
- * @param daemon daemon to set callback for
- * @param nsc function to call to check the policy
- * @param nsc_cls closure for @a apc
+ * @param daemon which instance should be configured
+ * @param mem_key private key (key.pem) to be used by the
+ *     HTTPS daemon.  Must be the actual data in-memory, not a filename.
+ * @param mem_cert certificate (cert.pem) to be used by the
+ *     HTTPS daemon.  Must be the actual data in-memory, not a filename.
+ * @param pass passphrase phrase to decrypt 'key.pem', NULL
+ *     if @param mem_key is in cleartext already
+ * @return #MHD_SC_OK upon success;
  */
 MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_notify_stream (struct MHD_Daemon *daemon,
-                              MHD_NotifyStreamCallback nsc,
-                              void *nsc_cls)
-MHD_FN_PAR_NONNULL_ (1);
-
-enum MHD_DaemonOptionSizet
-{
-  /**
-   * Maximum memory size per connection.
-   * Default is 32 kb (#MHD_POOL_SIZE_DEFAULT).
-   * Values above 128k are unlikely to result in much performance benefit,
-   * as half of the memory will be typically used for IO, and TCP buffers
-   * are unlikely to support window sizes above 64k on most systems.
-   * The size should be large enough to fit all request headers (together
-   * with internal parsing information).
-   */
-  MHD_DAEMON_OPTION_SIZET_CONN_MEM_LIMIT,
-  /**
-   * Desired size of the stack for threads created by MHD.
-   * Use 0 for system default, which is also MHD default.
-   * Only useful if the selected threading mode
-   * is not #MHD_TM_EXTERNAL_EVENT_LOOP.
-   */
-  MHD_DAEMON_OPTION_SIZET_STACK_SIZE,
+MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon,
+                                         const char *mem_key,
+                                         const char *mem_cert,
+                                         const char *pass)
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_PAR_NONNULL_ (3);
 
-};
-MHD_EXTERN_ void
-MHD_daemon_option_set_sizet (struct MHD_Daemon *daemon,
-                             enum MHD_DaemonOptionSizet option,
-                             size_t value)
-MHD_FN_PAR_NONNULL_ (1);
 
 /**
- * Set random values to be used by the Digest Auth module.  Note that
- * the application must ensure that @a buf remains allocated and
- * unmodified while the daemon is running.
+ * Configure DH parameters (dh.pem) to use for the TLS key
+ * exchange.
  *
- * @param daemon daemon to configure
- * @param buf_size number of bytes in @a buf
- * @param buf entropy buffer
+ * @param daemon daemon to configure tls for
+ * @param dh parameters to use
+ * @return #MHD_SC_OK upon success; TODO: define failure modes
  */
-MHD_EXTERN_ void
-MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon,
-                               size_t buf_size,
-                               const void *buf)
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3);
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon,
+                             const char *dh)
+MHD_FN_PAR_NONNULL_ (1);
 
 /**
- * Length of the internal array holding the map of the nonce and
- * the nonce counter.
+ * Memory pointer for the certificate (ca.pem) to be used by the
+ * HTTPS daemon for client authentication.
  *
- * @param daemon daemon to configure
- * @param nc_length desired array length
+ * @param daemon daemon to configure tls for
+ * @param mem_trust memory pointer to the certificate
+ * @return #MHD_SC_OK upon success; TODO: define failure modes
  */
 MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_digest_auth_nc_length (struct MHD_Daemon *daemon,
-                                      size_t nc_length)
+MHD_daemon_tls_mem_trust (struct MHD_Daemon *daemon,
+                          const char *mem_trust)
 MHD_FN_PAR_NONNULL_ (1);
 
-// FIXME: end of transform everything to option
 
-union MHD_DaemonOptionValue
+/* ********************** (d) TLS support ********************** */
+
+/**
+ * The TLS backend choice
+ */
+enum MHD_FIXED_ENUM_APP_SET_ MHD_TlsBackend
 {
-  enum MHD_Bool v_bool;
-  unsigned int v_uint;
-  size_t v_sizet;
-  struct MHD_DaemonOptionValueSA v_sa;
-  enum MHD_DaemonOptionAddrReuse v_addr_reuse;
+  /**
+   * Disable TLS, use plain TCP connections
+   */
+  MHD_TLS_BACKEND_NONE = 0
+  ,
+  /**
+   * Use best available TLS backend.
+   * Currently this is equivalent to GnuTLS (if TLS is enabled
+   * for MHD build).
+   */
+  MHD_TLS_BACKEND_ANY = 1
+  ,
+  /**
+   * Use GnuTLS as TLS backend.
+   */
+  MHD_TLS_BACKEND_GNUTLS = 2
 };
 
-struct MHD_DaemonOptionAndValue
+/**
+ * Values for #MHD_OPTION_DIGEST_AUTH_NONCE_BIND_TYPE.
+ *
+ * These values can limit the scope of validity of MHD-generated nonces.
+ * Values can be combined with bitwise OR.
+ * Any value, except #MHD_DAUTH_BIND_NONCE_NONE, enforce function
+ * #MHD_digest_auth_check() (and similar functions) to check nonce by
+ * re-generating it again with the same parameters, which is CPU-intensive
+ * operation.
+ */
+enum MHD_FIXED_FLAGS_ENUM_APP_SET_ MHD_DaemonOptionValueDAuthBindNonce
 {
   /**
-   * The daemon configuration option
+   * Generated nonces are valid for any request from any client until expired.
+   * This is default and recommended value.
+   * #MHD_digest_auth_check3() (and similar functions) would check only whether
+   * the nonce value that is used by client has been generated by MHD and not
+   * expired yet.
+   * It is recommended because RFC 7616 allows clients to use the same nonce
+   * for any request in the same "protection space".
+   * When checking client's authorisation requests CPU is loaded less if this
+   * value is used.
+   * This mode gives MHD maximum flexibility for nonces generation and can
+   * prevent possible nonce collisions (and corresponding log warning messages)
+   * when clients' requests are intensive.
+   * This value cannot be biwise-OR combined with other values.
    */
-  enum MHD_DaemonOption opt;
+  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_NONE = 0,
+
   /**
-   * The value for the @a opt option
+   * Generated nonces are valid only for the same realm.
    */
-  union MHD_DaemonOptionValue val;
-};
+  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_REALM = 1 << 0,
+
+  /**
+   * Generated nonces are valid only for the same URI (excluding parameters
+   * after '?' in URI) and request method (GET, POST etc).
+   * Not recommended unless "protection space" is limited to a single URI as
+   * RFC 7616 allows clients to re-use server-generated nonces for any URI
+   * in the same "protection space" which by default consists of all server
+   * URIs.
+   * Before #MHD_VERSION 0x00097701 this was default (and only supported)
+   * nonce bind type.
+   */
+  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_URI = 1 << 1,
 
+  /**
+   * Generated nonces are valid only for the same URI including URI parameters
+   * and request method (GET, POST etc).
+   * This value implies #MHD_DAUTH_BIND_NONCE_URI.
+   * Not recommended for that same reasons as #MHD_DAUTH_BIND_NONCE_URI.
+   */
+  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_URI_PARAMS = 1 << 2,
 
-#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT)
-/*  */ // TODO: no generic form
-#  define MHD_D_OPTION_BOOL_SET_(option,bool_val)  \
-  MHD_NOWARN_COMPOUND_LITERALS_                  \
-  (const struct MHD_DaemonOptionAndValue)        \
-  {                                              \
-    .opt = (option),                             \
-    .val.v_bool = (bool_val)                     \
-  }                                              \
-  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+  /**
+   * Generated nonces are valid only for the single client's IP.
+   * While it looks like security improvement, in practice the same client may
+   * jump from one IP to another (mobile or Wi-Fi handover, DHCP re-assignment,
+   * Multi-NAT, different proxy chain and other reasons), while IP address
+   * spoofing could be used relatively easily.
+   */
+  MHD_DAEMON_OPTION_VALUE_DAUTH_BIND_NONCE_CLIENT_IP = 1 << 3
+};
 
 /**
- * Bind to the given socket address.
- * Ineffective in conjunction with #MHD_daemon_listen_socket().
+ * Enable and configure TLS.
  *
- * @param sa address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6)
- *        or even a UNIX domain socket (AF_UNIX)
- * @param sa_len number of bytes in @a sa
- * @return the object of struct MHD_DaemonOptionAndValue with requested values
+ * @param daemon which instance should be configured
+ * @param tls_backend which TLS backend should be used,
+ *    currently only "gnutls" is supported.  You can
+ *    also specify NULL for best-available (which is the default).
+ * @return status code, #MHD_SC_OK upon success
+ *     #MHD_TLS_BACKEND_UNSUPPORTED if the @a backend is unknown
+ *     #MHD_TLS_DISABLED if this build of MHD does not support TLS
+ *     #MHD_TLS_CIPHERS_INVALID if the given @a ciphers are not supported
+ *     by this backend
  */
-#  define MHD_D_OPTION_SOCK_ADDR(sa_len_val,sa_val)       \
-  MHD_NOWARN_COMPOUND_LITERALS_                         \
-  (const struct MHD_DaemonOptionAndValue)               \
-  {                                                     \
-    .opt = (MHD_D_O_SA),                                \
-    .val.v_sa.sa_len = (sa_len_val),                    \
-    .val.v_sa.sa = (sa_val)                             \
-  }                                                     \
-  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_tls_backend (struct MHD_Daemon *daemon,
+                            enum MHD_TlsBackend backend)
+MHD_FN_PAR_NONNULL_ (1);
+
 
 /**
- * Terminate the list of the options
- * @return the terminating object of struct MHD_DaemonOptionAndValue
+ * Context required to provide a pre-shared key to the
+ * server.
+ *
+ * @param ...
+ * @param psk_size the number of bytes in @a psk
+ * @param psk the pre-shared-key; should be allocated with malloc(),
+ *                 will be freed by MHD
  */
-#  define MHD_D_OPTION_TERMINATE()                 \
-  MHD_NOWARN_COMPOUND_LITERALS_                  \
-  (const struct MHD_DaemonOptionAndValue)        \
-  {                                              \
-    .opt = (MHD_D_O_END)                         \
-  }                                              \
-  MHD_RESTORE_WARN_COMPOUND_LITERALS_
-
-#else  /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */
-MHD_NOWARN_UNUSED_FUNC_
+struct MHD_ServerCredentialsContext;
 
-/* Do not use directly */
-static MHD_INLINE struct MHD_DaemonOptionAndValue
-MHD_D_OPTION_BOOL_SET_(enum MHD_DaemonOption option,
-                  enum MHD_Bool bool_val)
-{
-  struct MHD_DaemonOptionAndValue opt_val;
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_connection_set_psk (struct MHD_ServerCredentialsContext *mscc,
+                        size_t psk_size,
+                        const /*void? */ char psk[MHD_C99_ (psk_size)]);
 
-  opt_val.opt = option;
-  opt_val.val.v_bool = bool_val;
+#define MHD_connection_set_psk_unavailable(mscc) \
+  MHD_connection_set_psk (mscc, 0, NULL)
 
-  return opt_val;
-}
 
 /**
- * Bind to the given socket address.
- * Ineffective in conjunction with #MHD_daemon_listen_socket().
+ * Function called to lookup the pre-shared key (PSK) for a given
+ * HTTP connection based on the @a username.  MHD will suspend handling of
+ * the @a connection until the application calls #MHD_connection_set_psk().
+ * If looking up the PSK fails, the application must still call
+ * #MHD_connection_set_psk_unavailable().
  *
- * @param sa_len_val the number of bytes in @a sa
- * @param sa_val the address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6)
- *        or even a UNIX domain socket (AF_UNIX)
- * @return the object of struct MHD_DaemonOptionAndValue with requested values
+ * @param cls closure
+ * @param connection the HTTPS connection
+ * @param username the user name claimed by the other side
+ * @param mscc context to pass to #MHD_connection_set_psk().
+ * @return 0 on success, -1 on errors
  */
-static MHD_INLINE struct MHD_DaemonOptionAndValue
-MHD_D_OPTION_SOCK_ADDR(size_t sa_len_val,
-                     const struct sockaddr *sa_val)
-{
-  struct MHD_DaemonOptionAndValue opt_val;
-
-  opt_val.opt = MHD_D_O_SA;
-  opt_val.val.v_sa.sa_len = sa_len_val;
-  opt_val.val.v_sa.sa = sa_val;
+typedef void
+(*MHD_PskServerCredentialsCallback)(void *cls,
+                                    const struct MHD_Connection *connection,
+                                    const struct MHD_String *username,
+                                    struct MHD_ServerCredentialsContext *mscc);
 
-  return opt_val;
-}
 
 /**
- * Terminate the list of the options
- * @return the terminating object of struct MHD_DaemonOptionAndValue
+ * Configure PSK to use for the TLS key exchange.
+ *
+ * @param daemon daemon to configure tls for
+ * @param psk_cb function to call to obtain pre-shared key
+ * @param psk_cb_cls closure for @a psk_cb
+ * @return #MHD_SC_OK upon success; TODO: define failure modes
  */
-static MHD_INLINE struct MHD_DaemonOptionAndValue
-MHD_D_OPTION_TERMINATE(void)
-{
-  struct MHD_DaemonOptionAndValue opt_val;
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_tls_psk_callback (struct MHD_Daemon *daemon,
+                                 MHD_PskServerCredentialsCallback psk_cb,
+                                 void *psk_cb_cls)
+MHD_FN_PAR_NONNULL_ (1);
 
-  opt_val.opt = MHD_D_O_END;
 
-  return opt_val;
-}
 
-MHD_RESTORE_WARN_UNUSED_FUNC_
-#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */
+// Callback invoked between full initialization of MHD
+// during MHD_daemon_start() and actual event loop
+// starting to accept incoming connections. So at this
+// point, the listen socket (and if applicable TLS context)
+// will be available for introspection.
+typedef void
+(*MHD_DaemonReadyCallback)(void *cls);
+
 
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_daemon_ready_callback (struct MHD_Daemon *daemon,
+                                      MHD_DaemonReadyCallback cb,
+                                      void *cb)
+MHD_FN_PAR_NONNULL_ (1);
 
 
 /**
- * Suppresses use of "Date:" header.
- * According to RFC should be used only if the system has no RTC.
- * @param bool_val the value of the parameter
- * @return the object of struct MHD_DaemonOptionAndValue with requested values
+ * Allow or deny a client to connect.
+ *
+ * @param cls closure
+ * @param addrlen length of @a addr
+ * @param addr address information from the client
+ * @see #MHD_daemon_accept_policy()
+ * @return #MHD_YES if connection is allowed, #MHD_NO if not
  */
-#define MHD_D_OPTION_SUPPRESS_DATE_HEADER(bool_val) \
-  MHD_D_OPTION_BOOL_SET_(MHD_D_O_BOOL_SUPPRESS_DATE_HEADER,(bool_val))
+typedef enum MHD_Bool
+(*MHD_AcceptPolicyCallback)(void *cls,
+                            size_t addr_len,
+                            const struct sockaddr *addr);
+
 
 /**
- * Disable #MHD_action_suspend() functionality.
+ * Set a policy callback that accepts/rejects connections
+ * based on the client's IP address.  This function will be called
+ * before a connection object is created.
  *
- * You should only use this function if you are sure you do
- * satisfy all of its requirements and need a generally minor
- * boost in performance.
- * @param bool_val the value of the parameter
- * @return the object of struct MHD_DaemonOptionAndValue with requested values
+ * @param daemon daemon to set policy for
+ * @param apc function to call to check the policy
+ * @param apc_cls closure for @a apc
  */
-#define MHD_D_OPTION_DISALLOW_SUSPEND_RESUME(bool_val) \
-  MHD_D_OPTION_BOOL_SET_(MHD_D_O_BOOL_DISALLOW_SUSPEND_RESUME,(bool_val))
+MHD_EXTERN_ void
+MHD_daemon_accept_policy (struct MHD_Daemon *daemon,
+                          MHD_AcceptPolicyCallback apc,
+                          void *apc_cls)
+MHD_FN_PAR_NONNULL_ (1);
 
 
 /**
- * Set the requested options for the daemon.
+ * Function called by MHD to allow the application to log
+ * the @a full_uri of a @a request.
+ * This is the only moment when unmodified URI is provided.
+ * After this callback MHD parses the URI and modifies it
+ * by extracting GET parameters in-place.
  *
- * If any option fail other options may be or may be not applied.
- * @param daemon the daemon to set the options
- * @param[in] options the pointer to the array with the options;
- *                    the array processing stops at the first ::MHD_D_O_END
- *                    option, but not later than after processing
- *                    @a options_max_num entries
- * @param options_max_num the maximum number of entries in the @a options,
- *                        use MHD_OPTIONS_ARRAY_MAX_SIZE if options processing
- *                        must stop only at zero-termination option
- * @return ::MHD_SC_OK on success,
- *         error code otherwise
+ * @param cls client-defined closure
+ * @param[in,out] request the HTTP request handle (headers are
+ *         not yet available)
+ * @param uri the full URI from the HTTP request including parameters (after '?')
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_options_set(struct MHD_Daemon *daemon,
-                       const struct MHD_DaemonOptionAndValue *options,
-                       size_t options_max_num)
-MHD_FN_PAR_NONNULL_ALL_;
+typedef void
+(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
+ *MHD_EarlyUriLogCallback)(void *cls,
+                           struct MHD_Request *request,
+                           const struct MHD_String *full_uri);
 
 
 /**
- * Set the requested single option for the daemon.
+ * Register a callback to be called first for every request
+ * (before any parsing of the header).  Makes it easy to
+ * log the full URL.
  *
- * @param daemon the daemon to set the option
- * @param[in] options the pointer to the option
- * @return ::MHD_SC_OK on success,
- *         error code otherwise
+ * @param daemon daemon for which to set the logger
+ * @param cb function to call
+ * @param cb_cls closure for @a cb
  */
-#define MHD_daemon_option_set(daemon, option_ptr) \
-  MHD_daemon_options_set(daemon, options_ptr, 1)
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_early_uri_logger (struct MHD_Daemon *daemon,
+                                 MHD_EarlyUriLogCallback cb,
+                                 void *cb_cls)
+MHD_FN_PAR_NONNULL_ (1);
 
 
-#ifdef MHD_USE_VARARG_MACROS
-MHD_NOWARN_VARIADIC_MACROS_
-#  if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_COMP_LIT_FUNC_PARAMS)
 /**
- * Set the requested options for the daemon.
- *
- * If any option fail other options may be or may be not applied.
- *
- * It should be used with helpers that creates required options, for example:
- *
- * MHD_DAEMON_OPTIONS_SET(d, MHD_D_OPTION_SUPPRESS_DATE_HEADER(MHD_YES),
- *                        MHD_D_OPTION_SOCK_ADDR(sa_len, sa))
- *
- * @param daemon the daemon to set the options
- * @param ... the list of the options, each option must be created
- *            by helpers MHD_DAEMON_OPTION_NameOfOption(option_value)
- * @return ::MHD_SC_OK on success,
- *         error code otherwise
+ * The `enum MHD_ConnectionNotificationCode` specifies types
+ * of connection notifications.
+ * @ingroup request
  */
-#    define MHD_DAEMON_OPTIONS_SET(daemon,...)      \
-  MHD_NOWARN_COMPOUND_LITERALS_                     \
-  MHD_daemon_options_set(daemon,                    \
-    ((const struct MHD_DaemonOptionAndValue[])      \
-       {__VA_ARGS__, MHD_D_OPTION_TERMINATE()}),       \
-    MHD_OPTIONS_ARRAY_MAX_SIZE)                     \
-  MHD_RESTORE_WARN_COMPOUND_LITERALS_
-#  elif defined(MHD_USE_CPP_INIT_LIST)
-} /* extern "C" */
-#    include <vector>
-extern "C"
+enum MHD_FIXED_ENUM_MHD_SET_ MHD_ConnectionNotificationCode
 {
-/**
- * Set the requested options for the daemon.
- *
- * If any option fail other options may be or may be not applied.
- *
- * It should be used with helpers that creates required options, for example:
- *
- * MHD_DAEMON_OPTIONS_SET(d, MHD_D_OPTION_SUPPRESS_DATE_HEADER(MHD_YES),
- *                        MHD_D_OPTION_SOCK_ADDR(sa_len, sa))
- *
- * @param daemon the daemon to set the options
- * @param ... the list of the options, each option must be created
- *            by helpers MHD_D_OPTION_NameOfOption(option_value)
- * @return ::MHD_SC_OK on success,
- *         error code otherwise
- */
-#    define MHD_DAEMON_OPTIONS_SET(daemon,...)      \
-  MHD_NOWARN_CPP_INIT_LIST_                         \
-  MHD_daemon_options_set(daemon,                      \
-    (std::vector<struct MHD_DaemonOptionAndValue>   \
-     {__VA_ARGS__,MHD_D_OPTION_TERMINATE()}).data(),   \
-    MHD_OPTIONS_ARRAY_MAX_SIZE)                     \
-  MHD_RESTORE_WARN_CPP_INIT_LIST_
-#  endif
-MHD_RESTORE_WARN_VARIADIC_MACROS_
-#endif /* MHD_USE_VARARG_MACROS && MHD_USE_COMP_LIT_FUNC_PARAMS */
 
+  /**
+   * A new connection has been started.
+   * @ingroup request
+   */
+  MHD_CONNECTION_NOTIFY_STARTED = 0
+  ,
+  /**
+   * A connection is closed.
+   * @ingroup request
+   */
+  MHD_CONNECTION_NOTIFY_CLOSED = 1
+
+};
 
-/* ******************* Event loop ************************ */
+/**
+ * Extra details for connection notifications.
+ * Currently not used
+ */
+union MHD_ConnectionNotificationDetails
+{
+  /**
+   * Unused
+   */
+  int reserved1;
+};
 
 
 /**
- * Which threading and polling mode should be used by MHD?
+ * The connection notification data structure
  */
-enum MHD_FIXED_ENUM_APP_SET_ MHD_WorkMode
+struct MHD_ConnectionNotificationData
 {
   /**
-   * The daemon has no internal threads.
-   * The application periodically calls #MHD_daemon_process_blocking(), where
-   * MHD internally checks all sockets automatically.
-   * This is the default.
+   * The connection handle
    */
-  MHD_WM_EXTERNAL_PERIODIC = 0
-  ,
+  struct MHD_Connection *connection;
   /**
-   * Use an external event loop with level triggers.
-   * Application uses #MHD_SocketRegistrationUpdateCallback, level triggered
-   * sockets polling (like select() or poll()) and #MHD_daemon_event_update().
+   * The connection-specific application context data (opaque for MHD).
+   * Initially set to NULL (for connections added by MHD) or set by
+   * @a connection_cntx parameter for connections added by
+   * #MHD_daemon_add_connection().
    */
-  MHD_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL = 8
-  ,
+  void *application_context;
   /**
-   * Use an external event loop with edge triggers.
-   * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered
-   * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update().
+   * The code of the event
    */
-  MHD_WM_EXTERNAL_EVENT_LOOP_CB_EDGE = 9
-  ,
+  enum MHD_ConnectionNotificationCode code;
   /**
-   * The daemon has no internal threads.
-   * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD
-   * that triggered when any MHD event happens.
-   * This FD can be watched as an aggregate indicator for all MHD events.
-   * This mode is available only on selected platforms (currently
-   * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD.
-   * When the FD is triggered, #MHD_daemon_process_nonblocking() should
-   * be called.
+   * Event details
    */
-  MHD_WM_EXTERNAL_SINGLE_FD_WATCH = 16
+  union MHD_ConnectionNotificationDetails details;
+};
+
+
+/**
+ * Signature of the callback used by MHD to notify the
+ * application about started/stopped network connections
+ *
+ * @param cls client-defined closure
+ * @param[in,out]  data the details about the event
+ * @see #MHD_daemon_set_notify_connection()
+ * @ingroup request
+ */
+typedef void
+(MHD_FN_PAR_NONNULL_ (2)
+ *MHD_NotifyConnectionCallback)(void *cls,
+                                struct MHD_ConnectionNotificationData *data);
+
+
+/**
+ * Register a function that should be called whenever a connection is
+ * started or closed.
+ *
+ * @param daemon daemon to set callback for
+ * @param ncc function to call to check the policy
+ * @param ncc_cls closure for @a apc
+ */
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_notify_connection (struct MHD_Daemon *daemon,
+                                  MHD_NotifyConnectionCallback ncc,
+                                  void *ncc_cls)
+MHD_FN_PAR_NONNULL_ (1);
+
+
+/**
+ * The type of stream notifications.
+ * @ingroup request
+ */
+enum MHD_FIXED_ENUM_MHD_SET_ MHD_StreamNotificationCode
+{
+  /**
+   * A new connection has been started.
+   * @ingroup request
+   */
+  MHD_STREAM_NOTIFY_STARTED = 0
   ,
   /**
-   * Run with one or more worker threads.
-   * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS is not specified
-   * then daemon starts with single worker thread that process
-   * all connections.
-   * If #MHD_DAEMON_OPTION_UINT_NUM_WORKERS used with value more
-   * than one, then that number of worker threads and distributed
-   * processing of requests among the workers.
+   * A connection is closed.
+   * @ingroup request
    */
-  MHD_WM_WORKER_THREADS = 24
-  ,
+  MHD_STREAM_NOTIFY_CLOSED = 1
 
+};
+
+/**
+ * Additional information about stream started event
+ */
+struct MHD_StreamNotificationDetailStarted
+{
   /**
-   * MHD should create its own thread for listening and furthermore create
-   * additional threads per every connection.  Use this if handling requests
-   * is CPU-intensive or blocking, your application is thread-safe and you
-   * have plenty of memory (per connection).
+   * Set to #MHD_YES of the stream was started by client
    */
-  MHD_WM_THREAD_PER_CONNECTION = 32
+  enum MHD_Bool by_client;
 };
 
-union MHD_WorkModeParam
+/**
+ * Additional information about stream events
+ */
+union MHD_StreamNotificationDetail
 {
-
+  /**
+   * Information for event #MHD_STREAM_NOTIFY_STARTED
+   */
+  struct MHD_StreamNotificationDetailStarted started;
 };
 
-struct MHD_WorkModeWithParam
+/**
+ * Stream notification data structure
+ */
+struct MHD_StreamNotificationData
 {
   /**
-   * The work mode for MHD
+   * The handle of the stream
    */
-  enum MHD_WorkMode mode;
+  struct MHD_Stream *stream;
   /**
-   * The parameters used for specified work mode
+   * The code of the event
+   */
+  enum MHD_StreamNotificationCode code;
+  /**
+   * Detailed information about notification event
    */
-  union MHD_WorkModeParam val;
+  union MHD_StreamNotificationDetail details;
 };
 
+
 /**
- * Specify threading mode to use.
+ * Signature of the callback used by MHD to notify the
+ * application about started/stopped data stream
+ * For HTTP/1.1 it is the same like network connection
+ * with 1:1 match.
  *
- * @param[in,out] daemon daemon to configure
- * @param tm mode to use
+ * @param cls client-defined closure
+ * @param data the details about the event
+ * @see #MHD_OPTION_NOTIFY_CONNECTION
+ * @ingroup request
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_daemon_set_threading_mode (struct MHD_Daemon *daemon,
-                               enum MHD_ThreadingMode tm)
-MHD_FN_PAR_NONNULL_ (1);
+typedef void
+(MHD_FN_PAR_NONNULL_ (2)
+ *MHD_NotifyStreamCallback)(
+   void *cls,
+   const struct MHD_StreamNotificationData *data);
 
 
 /**
- * The network status of the socket.
- * When set by MHD (by #MHD_get_watched_fds(), #MHD_get_watched_fds_update() and
- * similar) it indicates a request to watch for specific socket state:
- * readiness for receiving the data, readiness for sending the data and/or
- * exception state of the socket.
- * When set by application (and provided for #MHD_process_watched_fds() and
- * similar) it must indicate the actual status of the socket.
+ * Register a function that should be called whenever a stream is
+ * started or closed.
  *
- * Any actual state is a bitwise OR combination of #MHD_FD_STATE_RECV,
- * #MHD_FD_STATE_SEND, #MHD_FD_STATE_EXCEPT.
- * @ingroup event
+ * @param daemon daemon to set callback for
+ * @param nsc function to call to check the policy
+ * @param nsc_cls closure for @a apc
  */
-enum MHD_FIXED_ENUM_ MHD_FdState
-{
-  /**
-   * The socket is not ready for receiving or sending and
-   * does not have any exceptional state.
-   * The state never set by MHD, except de-registration of the sockets
-   * for #MHD_SocketRegistrationUpdateCallback().
-   */
-  MHD_FD_STATE_NONE = 0
-  ,
-  /* ** Three bit-flags ** */
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_notify_stream (struct MHD_Daemon *daemon,
+                              MHD_NotifyStreamCallback nsc,
+                              void *nsc_cls)
+MHD_FN_PAR_NONNULL_ (1);
 
+enum MHD_DaemonOptionSizet
+{
   /**
-   * Indicates that socket should be watched for incoming data
-   * (when set by #MHD_get_watched_fds())
-   * / socket has incoming data ready to read (when used for
-   * #MHD_process_watched_fds())
-   */
-  MHD_FD_STATE_RECV = 1 << 0,
-  /**
-   * Indicates that socket should be watched for availability for sending
-   * (when set by #MHD_get_watched_fds())
-   * / socket has ability to send data (when used for
-   * #MHD_process_watched_fds())
+   * Maximum memory size per connection.
+   * Default is 32 kb (#MHD_POOL_SIZE_DEFAULT).
+   * Values above 128k are unlikely to result in much performance benefit,
+   * as half of the memory will be typically used for IO, and TCP buffers
+   * are unlikely to support window sizes above 64k on most systems.
+   * The size should be large enough to fit all request headers (together
+   * with internal parsing information).
    */
-  MHD_FD_STATE_SEND = 1 << 1,
+  MHD_DAEMON_OPTION_SIZET_CONN_MEM_LIMIT,
   /**
-   * Indicates that socket should be watched for disconnect, out-of-band
-   * data available or high priority data available (when set by
-   * #MHD_get_watched_fds())
-   * / socket has been disconnected, has out-of-band data available or
-   * has high priority data available (when used for
-   * #MHD_process_watched_fds()). This status must not include "remote
-   * peer shut down writing" status.
-   * Note: #MHD_get_watched_fds() always set it as exceptions must be
-   * always watched.
+   * Desired size of the stack for threads created by MHD.
+   * Use 0 for system default, which is also MHD default.
+   * Only useful if the selected threading mode
+   * is not #MHD_TM_EXTERNAL_EVENT_LOOP.
    */
-  MHD_FD_STATE_EXCEPT = 1 << 2,
+  MHD_DAEMON_OPTION_SIZET_STACK_SIZE,
 
-  /* The rest of the list is a bit-wise combination of three main
-   * states. Application may use three main states directly as
-   * a bit-mask instead of using of following values
-   */
+};
+MHD_EXTERN_ void
+MHD_daemon_option_set_sizet (struct MHD_Daemon *daemon,
+                             enum MHD_DaemonOptionSizet option,
+                             size_t value)
+MHD_FN_PAR_NONNULL_ (1);
 
+/**
+ * Set random values to be used by the Digest Auth module.  Note that
+ * the application must ensure that @a buf remains allocated and
+ * unmodified while the daemon is running.
+ *
+ * @param daemon daemon to configure
+ * @param buf_size number of bytes in @a buf
+ * @param buf entropy buffer
+ */
+MHD_EXTERN_ void
+MHD_daemon_digest_auth_random (struct MHD_Daemon *daemon,
+                               size_t buf_size,
+                               const void *buf)
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3);
+
+/**
+ * Length of the internal array holding the map of the nonce and
+ * the nonce counter.
+ *
+ * @param daemon daemon to configure
+ * @param nc_length desired array length
+ */
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_set_digest_auth_nc_length (struct MHD_Daemon *daemon,
+                                      size_t nc_length)
+MHD_FN_PAR_NONNULL_ (1);
+
+// FIXME: end of transform everything to option
+
+union MHD_DaemonOptionValue
+{
+  enum MHD_Bool v_bool;
+  unsigned int v_uint;
+  size_t v_sizet;
+  struct MHD_DaemonOptionValueSA v_sa;
+  enum MHD_DaemonOptionAddrReuse v_addr_reuse;
+};
+
+struct MHD_DaemonOptionAndValue
+{
   /**
-   * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_SEND states.
-   */
-  MHD_FD_STATE_RECV_SEND = MHD_FD_STATE_RECV | MHD_FD_STATE_SEND,
-  /**
-   * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states.
-   */
-  MHD_FD_STATE_RECV_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT,
-  /**
-   * Combination of #MHD_FD_STATE_RECV and #MHD_FD_STATE_EXCEPT states.
+   * The daemon configuration option
    */
-  MHD_FD_STATE_SEND_EXCEPT = MHD_FD_STATE_RECV | MHD_FD_STATE_EXCEPT,
+  enum MHD_DaemonOption opt;
   /**
-   * Combination of #MHD_FD_STATE_RECV, #MHD_FD_STATE_SEND and
-   * #MHD_FD_STATE_EXCEPT states.
+   * The value for the @a opt option
    */
-  MHD_FD_STATE_RECV_SEND_EXCEPT = \
-    MHD_FD_STATE_RECV | MHD_FD_STATE_SEND | MHD_FD_STATE_EXCEPT
+  union MHD_DaemonOptionValue val;
 };
 
-/**
- * Checks whether specific @a state is enabled in @a var
- */
-#define MHD_FD_STATE_IS_SET(var,state)          \
-  (MHD_FD_STATE_NONE !=                         \
-   (((enum MHD_FdState) (var)) & ((enum MHD_FdState) (state))))
+
+#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT)
+/*  */ // TODO: no generic form
+#  define MHD_D_OPTION_BOOL_SET_(option,bool_val)  \
+  MHD_NOWARN_COMPOUND_LITERALS_                  \
+  (const struct MHD_DaemonOptionAndValue)        \
+  {                                              \
+    .opt = (option),                             \
+    .val.v_bool = (bool_val)                     \
+  }                                              \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
 
 /**
- * Checks whether RECV is enabled in @a var
- */
-#define MHD_FD_STATE_IS_SET_RECV(var) \
-  MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_RECV)
-/**
- * Checks whether SEND is enabled in @a var
+ * Bind to the given socket address.
+ * Ineffective in conjunction with #MHD_daemon_listen_socket().
+ *
+ * @param sa address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6)
+ *        or even a UNIX domain socket (AF_UNIX)
+ * @param sa_len number of bytes in @a sa
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-#define MHD_FD_STATE_IS_SET_SEND(var) \
-  MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_SEND)
+#  define MHD_D_OPTION_SOCK_ADDR(sa_len_val,sa_val)       \
+  MHD_NOWARN_COMPOUND_LITERALS_                         \
+  (const struct MHD_DaemonOptionAndValue)               \
+  {                                                     \
+    .opt = (MHD_D_O_SA),                                \
+    .val.v_sa.sa_len = (sa_len_val),                    \
+    .val.v_sa.sa = (sa_val)                             \
+  }                                                     \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+
 /**
- * Checks whether EXCEPT is enabled in @a var
+ * Terminate the list of the options
+ * @return the terminating object of struct MHD_DaemonOptionAndValue
  */
-#define MHD_FD_STATE_IS_SET_EXCEPT(var) \
-  MHD_FD_STATE_IS_SET ((var),MHD_FD_STATE_EXCEPT)
+#  define MHD_D_OPTION_TERMINATE()                 \
+  MHD_NOWARN_COMPOUND_LITERALS_                  \
+  (const struct MHD_DaemonOptionAndValue)        \
+  {                                              \
+    .opt = (MHD_D_O_END)                         \
+  }                                              \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+
+#else  /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */
+MHD_NOWARN_UNUSED_FUNC_
+
+/* Do not use directly */
+static MHD_INLINE struct MHD_DaemonOptionAndValue
+MHD_D_OPTION_BOOL_SET_(enum MHD_DaemonOption option,
+                  enum MHD_Bool bool_val)
+{
+  struct MHD_DaemonOptionAndValue opt_val;
+
+  opt_val.opt = option;
+  opt_val.val.v_bool = bool_val;
 
+  return opt_val;
+}
 
 /**
- * Enable specific @a state in @a var
+ * Bind to the given socket address.
+ * Ineffective in conjunction with #MHD_daemon_listen_socket().
+ *
+ * @param sa_len_val the number of bytes in @a sa
+ * @param sa_val the address to bind to; can be IPv4 (AF_INET), IPv6 (AF_INET6)
+ *        or even a UNIX domain socket (AF_UNIX)
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-#define MHD_FD_STATE_SET(var,state) \
-  (var) = (enum MHD_FdState) ((var) | (state))
+static MHD_INLINE struct MHD_DaemonOptionAndValue
+MHD_D_OPTION_SOCK_ADDR(size_t sa_len_val,
+                     const struct sockaddr *sa_val)
+{
+  struct MHD_DaemonOptionAndValue opt_val;
+
+  opt_val.opt = MHD_D_O_SA;
+  opt_val.val.v_sa.sa_len = sa_len_val;
+  opt_val.val.v_sa.sa = sa_val;
+
+  return opt_val;
+}
+
 /**
- * Enable RECV state in @a var
+ * Terminate the list of the options
+ * @return the terminating object of struct MHD_DaemonOptionAndValue
  */
-#define MHD_FD_STATE_SET_RECV(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_RECV)
+static MHD_INLINE struct MHD_DaemonOptionAndValue
+MHD_D_OPTION_TERMINATE(void)
+{
+  struct MHD_DaemonOptionAndValue opt_val;
+
+  opt_val.opt = MHD_D_O_END;
+
+  return opt_val;
+}
+
+MHD_RESTORE_WARN_UNUSED_FUNC_
+#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */
+
+
+
 /**
- * Enable SEND state in @a var
+ * Suppresses use of "Date:" header.
+ * According to RFC should be used only if the system has no RTC.
+ * @param bool_val the value of the parameter
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-#define MHD_FD_STATE_SET_SEND(var) MHD_FD_STATE_SET ((var),MHD_FD_STATE_SEND)
+#define MHD_D_OPTION_SUPPRESS_DATE_HEADER(bool_val) \
+  MHD_D_OPTION_BOOL_SET_(MHD_D_O_BOOL_SUPPRESS_DATE_HEADER,(bool_val))
+
 /**
- * Enable EXCEPT state in @a var
+ * Disable #MHD_action_suspend() functionality.
+ *
+ * You should only use this function if you are sure you do
+ * satisfy all of its requirements and need a generally minor
+ * boost in performance.
+ * @param bool_val the value of the parameter
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-#define MHD_FD_STATE_SET_EXCEPT(var) \
-  MHD_FD_STATE_SET ((var),MHD_FD_STATE_EXCEPT)
+#define MHD_D_OPTION_DISALLOW_SUSPEND_RESUME(bool_val) \
+  MHD_D_OPTION_BOOL_SET_(MHD_D_O_BOOL_DISALLOW_SUSPEND_RESUME,(bool_val))
+
 
 /**
- * Clear/disable specific @a state in @a var
+ * Set the requested options for the daemon.
+ *
+ * If any option fail other options may be or may be not applied.
+ * @param daemon the daemon to set the options
+ * @param[in] options the pointer to the array with the options;
+ *                    the array processing stops at the first ::MHD_D_O_END
+ *                    option, but not later than after processing
+ *                    @a options_max_num entries
+ * @param options_max_num the maximum number of entries in the @a options,
+ *                        use MHD_OPTIONS_ARRAY_MAX_SIZE if options processing
+ *                        must stop only at zero-termination option
+ * @return ::MHD_SC_OK on success,
+ *         error code otherwise
  */
-#define MHD_FD_STATE_CLEAR(var,state) \
-  (var) = (enum MHD_FdState) ((var) & (((enum MHD_FdState))(~state)))
+MHD_EXTERN_ enum MHD_StatusCode
+MHD_daemon_options_set(struct MHD_Daemon *daemon,
+                       const struct MHD_DaemonOptionAndValue *options,
+                       size_t options_max_num)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
 /**
- * Clear/disable RECV state in @a var
+ * Set the requested single option for the daemon.
+ *
+ * @param daemon the daemon to set the option
+ * @param[in] options the pointer to the option
+ * @return ::MHD_SC_OK on success,
+ *         error code otherwise
  */
-#define MHD_FD_STATE_CLEAR_RECV(var) \
-  MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_RECV)
+#define MHD_daemon_option_set(daemon, option_ptr) \
+  MHD_daemon_options_set(daemon, options_ptr, 1)
+
+
+#ifdef MHD_USE_VARARG_MACROS
+MHD_NOWARN_VARIADIC_MACROS_
+#  if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_COMP_LIT_FUNC_PARAMS)
 /**
- * Clear/disable SEND state in @a var
+ * Set the requested options for the daemon.
+ *
+ * If any option fail other options may be or may be not applied.
+ *
+ * It should be used with helpers that creates required options, for example:
+ *
+ * MHD_DAEMON_OPTIONS_SET(d, MHD_D_OPTION_SUPPRESS_DATE_HEADER(MHD_YES),
+ *                        MHD_D_OPTION_SOCK_ADDR(sa_len, sa))
+ *
+ * @param daemon the daemon to set the options
+ * @param ... the list of the options, each option must be created
+ *            by helpers MHD_DAEMON_OPTION_NameOfOption(option_value)
+ * @return ::MHD_SC_OK on success,
+ *         error code otherwise
  */
-#define MHD_FD_STATE_CLEAR_SEND(var) \
-  MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_SEND)
+#    define MHD_DAEMON_OPTIONS_SET(daemon,...)      \
+  MHD_NOWARN_COMPOUND_LITERALS_                     \
+  MHD_daemon_options_set(daemon,                    \
+    ((const struct MHD_DaemonOptionAndValue[])      \
+       {__VA_ARGS__, MHD_D_OPTION_TERMINATE()}),       \
+    MHD_OPTIONS_ARRAY_MAX_SIZE)                     \
+  MHD_RESTORE_WARN_COMPOUND_LITERALS_
+#  elif defined(MHD_USE_CPP_INIT_LIST)
+} /* extern "C" */
+#    include <vector>
+extern "C"
+{
 /**
- * Clear/disable EXCEPT state in @a var
+ * Set the requested options for the daemon.
+ *
+ * If any option fail other options may be or may be not applied.
+ *
+ * It should be used with helpers that creates required options, for example:
+ *
+ * MHD_DAEMON_OPTIONS_SET(d, MHD_D_OPTION_SUPPRESS_DATE_HEADER(MHD_YES),
+ *                        MHD_D_OPTION_SOCK_ADDR(sa_len, sa))
+ *
+ * @param daemon the daemon to set the options
+ * @param ... the list of the options, each option must be created
+ *            by helpers MHD_D_OPTION_NameOfOption(option_value)
+ * @return ::MHD_SC_OK on success,
+ *         error code otherwise
  */
-#define MHD_FD_STATE_CLEAR_EXCEPT(var) \
-  MHD_FD_STATE_CLEAR ((var),MHD_FD_STATE_EXCEPT)
-
+#    define MHD_DAEMON_OPTIONS_SET(daemon,...)      \
+  MHD_NOWARN_CPP_INIT_LIST_                         \
+  MHD_daemon_options_set(daemon,                      \
+    (std::vector<struct MHD_DaemonOptionAndValue>   \
+     {__VA_ARGS__,MHD_D_OPTION_TERMINATE()}).data(),   \
+    MHD_OPTIONS_ARRAY_MAX_SIZE)                     \
+  MHD_RESTORE_WARN_CPP_INIT_LIST_
+#  endif
+MHD_RESTORE_WARN_VARIADIC_MACROS_
+#endif /* MHD_USE_VARARG_MACROS && MHD_USE_COMP_LIT_FUNC_PARAMS */
 
-/* Changes:
- * + status update callback replaced with function
- * + status update accepts array of updates
- */
 
 /**
- * The context data to be used for updates of the socket state
+ * Create parameter for #MHD_daemon_options_set() for work mode with
+ * no internal threads.
+ * The application periodically calls #MHD_daemon_process_blocking(), where
+ * MHD internally checks all sockets automatically.
+ * This is the default mode.
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-struct MHD_EventUpdateContext;
+#define MHD_DAEMON_OPTION_WM_EXTERNAL_PERIODIC() \
+  MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_EXTERNAL_PERIODIC())
 
+/**
+* Create parameter for #MHD_daemon_options_set() for work mode with
+* an external event loop with level triggers.
+* Application uses #MHD_SocketRegistrationUpdateCallback, level triggered
+* sockets polling (like select() or poll()) and #MHD_daemon_event_update().
+* @param cb_val the callback for sockets registration
+* @param cb_cls_val the closure for the @a cv_val callback
+* @return the object of struct MHD_DaemonOptionAndValue with requested values
+*/
+#define MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL(cb_val,cb_cls_val) \
+  MHD_DAEMON_OPTION_WORK_MODE( \
+    MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_LEVEL((cb_val),(cb_cls_val)))
 
-/* Define MHD_APP_SOCKET_CNTX_TYPE to the socket context type before
- * including this header.
- * This is optional, but improves the types safety.
- * For example:
- * #define MHD_APP_SOCKET_CNTX_TYPE struct my_structure
+/**
+ * Create parameter for #MHD_daemon_options_set() for work mode with
+ * an external event loop with edge triggers.
+ * Application uses #MHD_SocketRegistrationUpdateCallback, edge triggered
+ * sockets polling (like epoll with EPOLLET) and #MHD_daemon_event_update().
+ * @param cb_val the callback for sockets registration
+ * @param cb_cls_val the closure for the @a cv_val callback
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-#ifndef MHD_APP_SOCKET_CNTX_TYPE
-#  define MHD_APP_SOCKET_CNTX_TYPE void
-#endif
+#define MHD_DAEMON_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_EDGE(cb_val,cb_cls_val) \
+  MHD_DAEMON_OPTION_WORK_MODE( \
+    MHD_WM_OPTION_EXTERNAL_EVENT_LOOP_CB_EDGE((cb_val),(cb_cls_val)))
 
 /**
- * The callback for registration/de-registration of the sockets to watch.
- *
- * This callback must not call #MHD_daemon_destroy(), #MHD_daemon_quiesce(),
- * #MHD_daemon_add_connection().
- *
- * @param cls the closure
- * @param fd the socket to watch
- * @param watch_for the states of the @a fd to watch, if set to
- *                  #MHD_FD_STATE_NONE the socket must be de-registred
- * @param app_cntx_old the old application defined context for the socket,
- *                     NULL if @a fd socket was not registered before
- * @param ecb_cntx the context handle to be used
- *                 with #MHD_daemon_event_update()
- * @return NULL if error (to connection will be closed),
- *         or the new socket context
- * @ingroup event
+ * Create parameter for #MHD_daemon_options_set() for work mode with
+ * no internal threads and aggregate watch FD.
+ * Application uses #MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD to get single FD
+ * that gets triggered by any MHD event.
+ * This FD can be watched as an aggregate indicator for all MHD events.
+ * This mode is available only on selected platforms (currently
+ * GNU/Linux only), see #MHD_LIB_INFO_FIXED_HAS_AGGREGATE_FD.
+ * When the FD is triggered, #MHD_daemon_process_nonblocking() should
+ * be called.
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-typedef MHD_APP_SOCKET_CNTX_TYPE *
-(MHD_FN_PAR_NONNULL_(5)
- *MHD_SocketRegistrationUpdateCallback)(
-  void *cls,
-  MHD_socket fd,
-  enum MHD_FdState watch_for,
-  MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old,
-  struct MHD_EventUpdateContext *ecb_cntx);
-
+#define MHD_DAEMON_OPTION_WM_EXTERNAL_SINGLE_FD_WATCH() \
+  MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_EXTERNAL_SINGLE_FD_WATCH())
 
 /**
- * Update the sockets state.
- * Must be called for every socket that got state updated.
- * For #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL mode should be called for each
- * socket.
- * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or
- * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes.
- * @param daemon the daemon handle
- * @param ecb_cntx the context handle provided
- *                 for #MHD_SocketRegistrationUpdateCallback
- * @param fd_current_state the current state of the socket
+ * Create parameter for #MHD_daemon_options_set() for work mode with
+ * one or more worker threads.
+ * If number of threads is one, then daemon starts with single worker thread
+ * that handles all connections.
+ * If number of threads is larger than one, then that number of worker threads,
+ * and handling of connection is distributed among the workers.
+ * @param num_workers the number of worker threads, zero is treated as one
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-MHD_EXTERN_ void
-MHD_daemon_event_update (
-  struct MHD_Daemon *daemon,
-  struct MHD_EventUpdateContext *ecb_cntx,
-  enum MHD_FdState fd_current_state)
-MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_NONNULL_(2);
-
+#define MHD_DAEMON_OPTION_WORKER_THREADS(num_workers) \
+  MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_WORKER_THREADS(num_workers))
 
 /**
- * Perform sockets registration, process registered network events.
- *
- * This function first processes all registered (by MHD_daemon_event_update())
- * network events (if any) and then calls #MHD_SocketRegistrationUpdateCallback
- * callback for every socket that needs to be added/updated/removed.
- *
- * Available only for daemons stated in #MHD_TM_EXTERNAL_EVENT_LOOP_CB_LEVEL or
- * #MHD_TM_EXTERNAL_EVENT_LOOP_CB_EDGE modes.
- *
- * @param daemon the daemon handle
- * @param[out] next_max_wait the optional pointer to receive the next maximum
- *                           wait time in microseconds to be used for sockets
- *                           polling function, can be NULL
- * @return MHD_SC_OK on success,
- *         error code otherwise
+ * Create parameter for #MHD_daemon_options_set() for work mode with
+ * one internal thread for listening and additional threads per every
+ * connection.  Use this if handling requests is CPU-intensive or blocking,
+ * your application is thread-safe and you have plenty of memory (per
+ * connection).
+ * @return the object of struct MHD_DaemonOptionAndValue with requested values
  */
-MHD_EXTERN_ enum MHD_StatusCode
-MHD_deamon_process_reg_events(struct MHD_Daemon *daemon,
-                              uint_fast64_t *next_max_wait)
-MHD_FN_PAR_NONNULL_(1);
+#define MHD_DAEMON_OPTION_THREAD_PER_CONNECTION() \
+  MHD_DAEMON_OPTION_WORK_MODE(MHD_WM_OPTION_THREAD_PER_CONNECTION())
+
+
+/* ******************* Event loop ************************ */
 
 
 /**