gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] 231/335: WIP more


From: gnunet
Subject: [libmicrohttpd] 231/335: WIP more
Date: Sat, 27 Jul 2024 22:02:07 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to tag stf-m2
in repository libmicrohttpd.

commit 189805ef3e7c24966f8299c080e8247cd6354c76
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Sun Jul 14 07:37:42 2024 +0200

    WIP more
---
 src/include/microhttpd2.h                          |  109 +-
 src/mhd2/Makefile.am                               |   37 +-
 src/mhd2/action.c                                  |   16 +-
 src/mhd2/conn_data_process.c                       |    7 +-
 src/mhd2/conn_data_process.h                       |   17 +-
 src/mhd2/conn_data_recv.c                          |   21 +-
 src/mhd2/conn_data_recv.h                          |    2 +-
 src/mhd2/conn_data_send.c                          |   24 +-
 src/mhd2/conn_data_send.h                          |    2 +-
 src/mhd2/daemon_add_conn.c                         |    8 +-
 src/mhd2/daemon_add_conn.h                         |   11 +
 src/mhd2/daemon_funcs.c                            |  135 +-
 src/mhd2/daemon_funcs.h                            |   85 +-
 src/mhd2/daemon_options.h                          |    6 +
 src/mhd2/daemon_start.c                            |  164 +-
 src/mhd2/http_prot_ver.h                           |   13 +
 src/mhd2/http_status_str.c                         |   10 +-
 src/mhd2/http_status_str.h                         |    2 +-
 src/mhd2/mhd_action.h                              |   45 +-
 src/mhd2/mhd_atomic_counter.c                      |   17 +-
 src/mhd2/mhd_atomic_counter.h                      |   18 +-
 src/mhd2/{http_status_str.h => mhd_buffer.h}       |   37 +-
 src/mhd2/mhd_connection.h                          |   62 +-
 src/mhd2/mhd_daemon.h                              |   43 +
 src/mhd2/mhd_mempool.c                             |   54 +-
 src/mhd2/mhd_mempool.h                             |   52 +-
 src/mhd2/mhd_recv.c                                |   15 +-
 src/mhd2/mhd_reply.h                               |    6 -
 src/mhd2/mhd_request.h                             |   42 +-
 src/mhd2/mhd_response.h                            |    2 +-
 src/mhd2/mhd_send.c                                |  190 ++-
 src/mhd2/mhd_socket_error.c                        |    7 +-
 src/mhd2/mhd_str.h                                 |   24 +-
 src/mhd2/request_funcs.c                           |   13 +-
 src/mhd2/request_get_value.c                       |   32 +-
 src/mhd2/request_get_value.h                       |   32 +-
 src/mhd2/respond_with_error.h                      |   86 +
 src/mhd2/response_add_header.c                     |   35 +-
 src/mhd2/response_destroy.c                        |   14 +-
 src/mhd2/response_funcs.c                          |   23 +-
 src/mhd2/response_set_options.c                    |    1 +
 src/mhd2/stream_funcs.c                            |  117 +-
 src/mhd2/stream_funcs.h                            |   85 +-
 .../{http_status_str.h => stream_process_reply.h}  |   24 +-
 src/mhd2/stream_process_request.c                  | 1735 ++++++++++++++++----
 src/mhd2/stream_process_request.h                  |  125 +-
 src/mhd2/stream_process_states.c                   |  149 +-
 47 files changed, 2874 insertions(+), 880 deletions(-)

diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
index b1e1b2b2..4c304c5e 100644
--- a/src/include/microhttpd2.h
+++ b/src/include/microhttpd2.h
@@ -481,6 +481,17 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
   MHD_SC_CONNECTION_POOL_MALLOC_FAILURE_REQ = 30130
   ,
+  /**
+   * Failed to allocate memory from our memory pool to store GET parameter.
+   * Likely the request URI or header fields are too large to leave enough 
room.
+   */
+  MHD_SC_CONNECTION_POOL_NO_MEM_GET_PARAM = 30131
+  ,
+  /**
+   * Failed to allocate memory from our memory pool to store parsed cookie.
+   */
+  MHD_SC_CONNECTION_POOL_NO_MEM_COOKIE = 30132
+  ,
 
   /* 40000-level errors are caused by the HTTP client
      (or the network) */
@@ -497,42 +508,57 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
   MHD_SC_CONNECTION_RESET_CLOSED = 40001
   ,
   /**
-   * MHD is closing a connection because reading the
+   * MHD is closing a connection because receiving the
    * request failed.
    */
-  MHD_SC_CONNECTION_READ_FAIL_CLOSED = 40002
+  MHD_SC_CONNECTION_RECV_FAIL_CLOSED = 40002
   ,
   /**
-   * MHD is closing a connection because writing the response failed.
+   * MHD is closing a connection because sending the response failed.
    */
-  MHD_SC_CONNECTION_WRITE_FAIL_CLOSED = 40003
+  MHD_SC_CONNECTION_SEND_FAIL_CLOSED = 40003
   ,
   /**
    * MHD is returning an error because the header provided
    * by the client is too big.
    */
-  MHD_SC_CLIENT_HEADER_TOO_BIG = 40004
+  MHD_SC_CLIENT_HEADER_TOO_BIG = 40020
   ,
   /**
    * An HTTP/1.1 request was sent without the "Host:" header.
    */
-  MHD_SC_HOST_HEADER_MISSING = 40005
+  MHD_SC_HOST_HEADER_MISSING = 40060
   ,
   /**
    * The given content length was not a number.
    */
-  MHD_SC_CONTENT_LENGTH_MALFORMED = 40006
+  MHD_SC_CONTENT_LENGTH_MALFORMED = 40061
+  ,
+  /**
+   * The BOTH Content-Length and Transfer-Encoding headers are used.
+   */
+  MHD_SC_CONTENT_LENGTH_AND_TR_ENC = 40062
+  ,
+  /**
+   * The Content-Length is too large to be handled.
+   */
+  MHD_SC_CONTENT_LENGTH_TOO_LARGE = 40062
   ,
   /**
    * The given uploaded, chunked-encoded body was malformed.
    */
-  MHD_SC_CHUNKED_ENCODING_MALFORMED = 40007
+  MHD_SC_CHUNKED_ENCODING_MALFORMED = 40080
   ,
   /**
    * The first header line has whitespace at the start
    */
   MHD_SC_REQ_FIRST_HEADER_LINE_SPACE_PREFIXED = 40100
   ,
+  /**
+   * The request target (URI) has whitespace character
+   */
+  MHD_SC_REQ_TARGET_HAS_WHITESPACE = 40101
+  ,
   /**
    * Wrong bare CR characters has been replaced with space.
    */
@@ -553,6 +579,28 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
   MHD_SC_REQ_FOOTER_LINE_NO_COLON = 40141
   ,
+  /**
+   * The cookie string has been parsed, but it is not fully compliant with
+   * specifications
+   */
+  MHD_SC_REQ_COOKIE_PARSED_NOT_COMPLIANT = 40142
+  ,
+  /**
+   * The cookie string has been parsed only partially
+   */
+  MHD_SC_REQ_COOKIE_PARSED_PARTIALLY = 40142
+  ,
+  /**
+   * The cookie string is ignored, as it is not fully compliant with
+   * specifications
+   */
+  MHD_SC_REQ_COOKIE_IGNORED_NOT_COMPLIANT = 40143
+  ,
+  /**
+   * The cookie string has been ignored as it is invalid
+   */
+  MHD_SC_REQ_COOKIE_INVALID = 40143
+  ,
 
   /* 50000-level errors are because of an error internal
      to the MHD logic, possibly including our interaction
@@ -785,6 +833,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
   MHD_SC_LISTEN_PORT_INTROSPECTION_UNKNOWN_AF = 50081
   ,
+  /**
+   * Failed to initialise mutex.
+   */
+  MHD_SC_MUTEX_INIT_FAILURE = 50085
+  ,
   /**
    * Failed to allocate memory for the thread pool.
    */
@@ -1163,6 +1216,16 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    * The response header value has forbidden characters
    */
   MHD_SC_RESP_HEADER_VALUE_INVALID = 60051
+  ,
+  /**
+   * The the provided MHD_Action is invalid
+   */
+  MHD_SC_ACTION_INVALID = 60080
+  ,
+  /**
+   * The the provided MHD_UploadAction is invalid
+   */
+  MHD_SC_UPLOAD_ACTION_INVALID = 60081
 
 };
 
@@ -1997,7 +2060,7 @@ MHD_FN_CONST_;
  *                    #MHD_SIZE_UNKNOWN for chunked uploads (if the
  *                    final chunk has not been processed yet)
  * @return action how to proceed, NULL
- *         if the request must be closed due to a serious
+ *         if the request must be aborted due to a serious
  *         error while handling the request (implies closure
  *         of underling data stream, for HTTP/1.1 it means
  *         socket closure).
@@ -2259,7 +2322,7 @@ struct MHD_EventUpdateContext;
  *                     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),
+ * @return NULL if error (to connection will be aborted),
  *         or the new socket context
  * @ingroup event
  */
@@ -3238,13 +3301,13 @@ typedef void
 enum MHD_FIXED_ENUM_MHD_SET_ MHD_StreamNotificationCode
 {
   /**
-   * A new connection has been started.
+   * A new stream has been started.
    * @ingroup request
    */
   MHD_STREAM_NOTIFY_STARTED = 0
   ,
   /**
-   * A connection is closed.
+   * A stream is closed.
    * @ingroup request
    */
   MHD_STREAM_NOTIFY_CLOSED = 1
@@ -4723,7 +4786,7 @@ MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_OUT_SIZE_ (4,3);
  * @return NULL if no such item was found
  * @ingroup request
  */
-MHD_EXTERN_ const struct MHD_String *
+MHD_EXTERN_ const struct MHD_StringNullable *
 MHD_request_get_value (struct MHD_Request *MHD_RESTRICT request,
                        enum MHD_ValueKind kind,
                        const char *MHD_RESTRICT key)
@@ -5122,7 +5185,7 @@ MHD_FN_PAR_NONNULL_ALL_;
  * @param request the request to create the action for
  * @param[in] response the response to convert,
  *                     if NULL then this function is equivalent to
- *                     #MHD_action_close_connection() call
+ *                     #MHD_action_abort_connection() call
  * @return pointer to the action, the action must be consumed
  *         otherwise response object may leak;
  *         NULL if failed (no memory) or if any action has been already
@@ -5145,7 +5208,7 @@ MHD_FN_PAR_NONNULL_(1);
  * @return action operation, always NULL
  * @ingroup action
  */
-#define MHD_action_close_connection(req) \
+#define MHD_action_abort_request(req) \
         MHD_STATIC_CAST_ (const struct MHD_Action *, NULL)
 
 
@@ -5674,7 +5737,7 @@ MHD_FN_RETURNS_NONNULL_ MHD_FN_PAR_NONNULL_ALL_;
  * @param request the request to create the action for
  * @param[in] response the response to convert,
  *                     if NULL then this function is equivalent to
- *                     #MHD_upload_action_close_connection() call
+ *                     #MHD_upload_action_abort_request() call
  * @return pointer to the action, the action must be consumed
  *         otherwise response object may leak;
  *         NULL if failed (no memory) or if any action has been already
@@ -5690,6 +5753,9 @@ MHD_FN_PAR_NONNULL_(1);
 
 /**
  * Action telling MHD to continue processing the upload.
+ * Valid only for incremental upload processing.
+ * Works as #MHD_upload_action_abort_request() if used for full upload callback
+ * or for the final (with zero data) incremental callback.
  *
  * @param request the request to make an action
  * @return action operation,
@@ -5709,7 +5775,7 @@ MHD_FN_RETURNS_NONNULL_;
  * @return action operation, always NULL
  * @ingroup action
  */
-#define MHD_upload_action_close_connection(req) \
+#define MHD_upload_action_abort_request(req) \
         MHD_STATIC_CAST_ (const struct MHD_UploadAction *, NULL)
 
 #ifndef MHD_UPLOADCALLBACK_DEFINED
@@ -5727,10 +5793,11 @@ MHD_FN_RETURNS_NONNULL_;
  *                         valid only until return from the callback,
  *                         NULL when all data have been processed
  * @return action specifying how to proceed:
- *         #MHD_upload_action_continue() if all is well,
+ *         #MHD_upload_action_continue() to continue upload (for incremental
+ *         upload processing only),
  *         #MHD_upload_action_suspend() to stop reading the upload until
  *         the request is resumed,
- *         #MHD_upload_action_close_connection() to close the socket,
+ *         #MHD_upload_action_abort_request() to close the socket,
  *         or a response to discard the rest of the upload and transmit
  *         the response
  * @ingroup action
@@ -5833,7 +5900,7 @@ MHD_FN_PAR_NONNULL_ (1);
  *         #MHD_upload_action_continue() if all is well,
  *         #MHD_upload_action_suspend() to stop reading the upload until
  *         the request is resumed,
- *         #MHD_upload_action_close_connection() to close the socket,
+ *         #MHD_upload_action_abort_request() to close the socket,
  *         or a response to discard the rest of the upload and transmit
  *         the response
  * @ingroup action
@@ -5890,7 +5957,7 @@ typedef const struct MHD_UploadAction *
  * @sa #MHD_D_OPTION_LARGE_POOL_SIZE()
  * @ingroup action
  */
-MHD_EXTERN_ struct MHD_Action *
+MHD_EXTERN_ const struct MHD_Action *
 MHD_action_post_processor (struct MHD_Request *request,
                            size_t pp_buffer_size,
                            size_t pp_stream_limit, // FIXME: Remove? 
Duplicated with pp_buffer_size
diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am
index 1c569739..fa855adc 100644
--- a/src/mhd2/Makefile.am
+++ b/src/mhd2/Makefile.am
@@ -26,25 +26,38 @@ libmicrohttpd2_la_SOURCES = \
   autoinit_funcs.h \
   sys_null_macro.h          sys_base_types.h          sys_bool_type.h \
   sys_sockets_types.h       sys_sockets_headers.h     sys_ip_headers.h \
-  sys_errno.h               sys_malloc.h \
+  sys_errno.h               sys_file_fd.h             sys_malloc.h \
   sys_poll.h \
   sys_sendfile.h \
   compat_calloc.h \
   mhd_assert.h \
   mhd_tristate.h \
-  mhd_socket_types.h        mhd_sockets_macros.h \
+  mhd_socket_type.h         mhd_sockets_macros.h \
   mhd_sockets_funcs.c       mhd_sockets_funcs.h \
+  mhd_socket_error.c        mhd_socket_error.h \
+  mhd_atomic_counter.c      mhd_atomic_counter.h \
+  mhd_str.c                 mhd_str.h \
+  mhd_str_macros.h          mhd_str_types.h \
+  mhd_buffer.h \
+  mhd_limits.h \
   mhd_iovec.h \
   mhd_panic.c               mhd_panic.h \
   mhd_lib_init.c            mhd_lib_init_impl.h       mhd_lib_init.h \
   mhd_dlinked_list.h \
+  mhd_connection.h \
   mhd_locks.h \
   mhd_itc.c                 mhd_itc.h                 mhd_itc_types.h \
   mhd_threads.c             mhd_threads.h             sys_thread_entry_type.h \
   mhd_mono_clock.c          mhd_mono_clock.h \
   mhd_mempool.c             mhd_mempool.h \
-  mhd_daemon.h              daemon_funcs.c            daemon_funcs.h \
+  mhd_recv.c                mhd_recv.h \
+  mhd_send.c                mhd_send.h \
+  mhd_daemon.h \
   mhd_public_api.h \
+  mhd_request.h             mhd_reply.h               mhd_response.h \
+  http_method.h             http_prot_ver.h \
+  http_status_str.c         http_status_str.h \
+  action.c                  mhd_action.h \
   events_process.c          events_process.h \
   daemon_logger.c           daemon_logger.h \
   daemon_logger_default.c   daemon_logger_default.h \
@@ -52,9 +65,21 @@ libmicrohttpd2_la_SOURCES = \
   daemon_create.c \
   daemon_start.c \
   daemon_add_conn.c         daemon_add_conn.h \
-  mhd_connection.h          mhd_request.h             mhd_reply.h \
-  response_from.c           response_from.h
-
+  daemon_funcs.c            daemon_funcs.h \
+  conn_data_process.c       conn_data_process.h \
+  conn_data_recv.c          conn_data_recv.h \
+  request_funcs.c           request_funcs.h \
+  request_get_value.c       request_get_value.h \
+  respond_with_error.h \
+  response_from.c           response_from.h \
+  response_add_header.c     response_add_header.h \
+  response_destroy.c        response_destroy.h \
+  response_funcs.c          response_funcs.h \
+  response_set_options.c    response_set_options.h    response_options.h \
+  stream_funcs.c            stream_funcs.h \
+  stream_process_states.c   stream_process_states.h \
+  stream_process_request.c  stream_process_request.h \
+  stream_process_reply.h
 
 if ! HAVE_SYS_CALLOC
 libmicrohttpd2_la_SOURCES += \
diff --git a/src/mhd2/action.c b/src/mhd2/action.c
index 9f37cf12..0971832a 100644
--- a/src/mhd2/action.c
+++ b/src/mhd2/action.c
@@ -37,7 +37,7 @@ const struct MHD_Action *
 MHD_action_suspend (struct MHD_Request *request)
 {
   struct MHD_Action *const restrict head_act = &(request->app_act.head_act);
-  if (mhd_UPLOAD_ACTION_NO_ACTION != head_act->act)
+  if (mhd_ACTION_NO_ACTION != head_act->act)
     return (const struct MHD_Action *) NULL;
 
   head_act->act = mhd_ACTION_SUSPEND;
@@ -100,7 +100,7 @@ MHD_action_process_upload (struct MHD_Request *request,
 
 
 MHD_EXTERN_
-MHD_FN_PAR_NONNULL_ (1) struct MHD_Action *
+MHD_FN_PAR_NONNULL_ (1) const struct MHD_Action *
 MHD_action_post_processor (struct MHD_Request *request,
                            size_t pp_buffer_size,
                            size_t pp_stream_limit,
@@ -110,7 +110,8 @@ MHD_action_post_processor (struct MHD_Request *request,
                            MHD_PostDataFinished done_cb,
                            void *done_cb_cls)
 {
-  struct MHD_Action *const restrict head_act = &(request->app_act.head_act);
+  struct MHD_Action *const restrict head_act =
+    &(request->app_act.head_act);
   if (mhd_ACTION_NO_ACTION != head_act->act)
     return (const struct MHD_Action *) NULL;
   if (NULL == done_cb)
@@ -133,7 +134,8 @@ MHD_EXTERN_ MHD_FN_RETURNS_NONNULL_ MHD_FN_PAR_NONNULL_ALL_
 const struct MHD_UploadAction *
 MHD_upload_action_suspend (struct MHD_Request *request)
 {
-  struct MHD_Action *const restrict upl_act = &(request->app_act.upl_act);
+  struct MHD_UploadAction *const restrict upl_act =
+    &(request->app_act.upl_act);
   if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
     return (const struct MHD_UploadAction *) NULL;
 
@@ -148,7 +150,8 @@ MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction *
 MHD_upload_action_from_response (struct MHD_Request *request,
                                  struct MHD_Response *response)
 {
-  struct MHD_Action *const restrict upl_act = &(request->app_act.upl_act);
+  struct MHD_UploadAction *const restrict upl_act =
+    &(request->app_act.upl_act);
   if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
     return (const struct MHD_UploadAction *) NULL;
 
@@ -162,7 +165,8 @@ MHD_upload_action_from_response (struct MHD_Request 
*request,
 MHD_EXTERN_ MHD_FN_RETURNS_NONNULL_ const struct MHD_UploadAction *
 MHD_upload_action_continue (struct MHD_Request *request)
 {
-  struct MHD_Action *const restrict upl_act = &(request->app_act.upl_act);
+  struct MHD_UploadAction *const restrict upl_act =
+    &(request->app_act.upl_act);
   if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
     return (const struct MHD_UploadAction *) NULL;
 
diff --git a/src/mhd2/conn_data_process.c b/src/mhd2/conn_data_process.c
index 0b364d2b..c1a3b6bb 100644
--- a/src/mhd2/conn_data_process.c
+++ b/src/mhd2/conn_data_process.c
@@ -44,6 +44,7 @@
 
 #include "conn_data_recv.h"
 #include "conn_data_send.h"
+#include "stream_process_states.h"
 
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
 mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
@@ -62,7 +63,7 @@ mhd_conn_process_recv_send_data (struct MHD_Connection 
*restrict c)
     bool use_recv;
     use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY & c->sk_ready));
     use_recv = use_recv ||
-      (has_sock_err && c->sk_nonblck);
+               (has_sock_err && c->sk_nonblck);
 
     if (use_recv)
     {
@@ -86,9 +87,9 @@ mhd_conn_process_recv_send_data (struct MHD_Connection 
*restrict c)
        or has not been performed yet. */
     use_send = (0 != (mhd_SOCKET_NET_STATE_SEND_READY & c->sk_ready));
     use_send = use_send ||
-      (data_processed && (! send_ready_state_known) && c->sk_nonblck);
+               (data_processed && (! send_ready_state_known) && c->sk_nonblck);
     use_send = use_send ||
-      (has_sock_err && c->sk_nonblck);
+               (has_sock_err && c->sk_nonblck);
 
     if (use_send)
     {
diff --git a/src/mhd2/conn_data_process.h b/src/mhd2/conn_data_process.h
index 1ad1dee2..5667bbfc 100644
--- a/src/mhd2/conn_data_process.h
+++ b/src/mhd2/conn_data_process.h
@@ -40,16 +40,17 @@ struct MHD_Connection; /* forward declaration */
  */
 MHD_INTERNAL bool
 mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
-MHD_FN_PAR_NONNULL_ALL_ ;
+MHD_FN_PAR_NONNULL_ALL_;
 
 /**
- * Finally close and clean-up connection.
- * Must be performed only when connection thread (for thread-per-connection)
- * has stopped.
- * @param c the connection to close
+ * Update "active" state, move to the activity lists if necessary.
+ * Update "event loop info"
+ * @param c the connection to use
+ * @return true if data processed successfully,
+ *         false if connection needs to be closed
  */
-MHD_INTERNAL void
-mhd_conn_close_final (struct MHD_Connection *restrict c)
-MHD_FN_PAR_NONNULL_ALL_ ;
+MHD_INTERNAL bool
+mhd_conn_update_active_state (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
 
 #endif /* ! MHD_DATA_PROCESS_H */
diff --git a/src/mhd2/conn_data_recv.c b/src/mhd2/conn_data_recv.c
index bf0bc3ec..15ae732d 100644
--- a/src/mhd2/conn_data_recv.c
+++ b/src/mhd2/conn_data_recv.c
@@ -1,7 +1,6 @@
 /*
   This file is part of GNU libmicrohttpd
-  Copyright (C) 2015-2024 Evgeny Grin (Karlson2k)
-  Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
 
   GNU libmicrohttpd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -23,9 +22,6 @@
  * @file src/mhd2/conn_data_recv.c
  * @brief  The implementation of data receiving functions for connection
  * @author Karlson2k (Evgeny Grin)
- *
- * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff, Evgeny 
Grin
- * and other contributors.
  */
 
 #include "conn_data_recv.h"
@@ -40,13 +36,12 @@
 #include "mhd_connection.h"
 
 #include "mhd_recv.h"
+#include "stream_funcs.h"
 
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_conn_data_recv (struct MHD_Connection restrict *c,
-                       bool has_err)
+mhd_conn_data_recv (struct MHD_Connection *restrict c,
+                    bool has_err)
 {
-  ssize_t bytes_read;
-  uint_fast64_t dummy_buf;
   void *buf;
   size_t buf_size;
   size_t received;
@@ -74,7 +69,7 @@ mhd_conn_data_recv (struct MHD_Connection restrict *c,
     {
       /* Re-try last time to detect the error */
       uint_fast64_t dummy_buf;
-      res = mhd_recv (c, &dummy_buf, sizeof(dummy_buf), &received);
+      res = mhd_recv (c, sizeof(dummy_buf), (char *) &dummy_buf, &received);
     }
     if (mhd_SOCKET_ERR_IS_HARD (res))
     {
@@ -86,11 +81,11 @@ mhd_conn_data_recv (struct MHD_Connection restrict *c,
     return;
   }
 
-  if (0 == bytes_read)
+  if (0 == received)
     c->sk_rmt_shut_wr = true;
 
-  c->read_buffer_offset += (size_t) bytes_read;
-  MHD_update_last_activity_ (c); // TODO: centralise activity update
+  c->read_buffer_offset += received;
+  mhd_stream_update_activity_mark (c); // TODO: centralise activity update
   return;
 }
 
diff --git a/src/mhd2/conn_data_recv.h b/src/mhd2/conn_data_recv.h
index 927f103a..9edc4aeb 100644
--- a/src/mhd2/conn_data_recv.h
+++ b/src/mhd2/conn_data_recv.h
@@ -42,7 +42,7 @@ struct MHD_Connection; /* forward declarations */
  *        type is performed
  */
 MHD_INTERNAL void
-mhd_conn_data_recv (struct MHD_Connection restrict *c,
+mhd_conn_data_recv (struct MHD_Connection *restrict c,
                     bool has_err)
 MHD_FN_PAR_NONNULL_ALL_;
 
diff --git a/src/mhd2/conn_data_send.c b/src/mhd2/conn_data_send.c
index 2f4cd6e0..fa15f344 100644
--- a/src/mhd2/conn_data_send.c
+++ b/src/mhd2/conn_data_send.c
@@ -69,13 +69,13 @@ check_write_done (struct MHD_Connection *restrict 
connection,
 
 
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_conn_data_send (struct MHD_Connection restrict *c,
+mhd_conn_data_send (struct MHD_Connection *restrict c,
                     bool has_err)
 {
   static const char http_100_continue_msg[] =
     mdh_HTTP_1_1_100_CONTINUE_REPLY;
   static const size_t http_100_continue_msg_len =
-      mhd_SSTR_LEN(mdh_HTTP_1_1_100_CONTINUE_REPLY);
+    mhd_SSTR_LEN (mdh_HTTP_1_1_100_CONTINUE_REPLY);
   enum mhd_SocketError res;
   size_t sent;
 
@@ -121,8 +121,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
       mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
 
       res = mhd_send_hdr_and_body (c,
-                                   c->write_buffer +
-                                   c->write_buffer_send_offset,
+                                   c->write_buffer
+                                   + c->write_buffer_send_offset,
                                    wb_ready,
                                    false,
                                    (const char *) resp->cntn.buf,
@@ -136,8 +136,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
        * for any other reason or reply body is dynamically generated. */
       /* Do not send the body data even if it's available. */
       res = mhd_send_hdr_and_body (c,
-                                   c->write_buffer +
-                                   c->write_buffer_send_offset,
+                                   c->write_buffer
+                                   + c->write_buffer_send_offset,
                                    wb_ready,
                                    false,
                                    NULL,
@@ -183,8 +183,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
       mhd_assert (mhd_RESPONSE_CONTENT_DATA_BUFFER == resp->cntn_dtype);
 
       res = mhd_send_data (c,
-                           (const char *) resp->cntn.buf +
-                           c->rp.rsp_cntn_read_pos,
+                           (const char *) resp->cntn.buf
+                           + c->rp.rsp_cntn_read_pos,
                            c->rp.rsp_cntn_read_pos - resp->cntn_size,
                            true,
                            &sent);
@@ -245,8 +245,8 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
   else if (MHD_CONNECTION_FOOTERS_SENDING == c->state)
   {
     res = mhd_send_data (c,
-                         c->write_buffer +
-                         c->write_buffer_send_offset,
+                         c->write_buffer
+                         + c->write_buffer_send_offset,
                          c->write_buffer_append_offset
                          - c->write_buffer_send_offset,
                          true,
@@ -267,9 +267,9 @@ mhd_conn_data_send (struct MHD_Connection restrict *c,
 
   if (mhd_SOCKET_ERR_NO_ERROR != res)
   {
-    MHD_update_last_activity_ (c);  // TODO: centralise activity mark updates
+    mhd_stream_update_activity_mark (c);  // TODO: centralise activity mark 
updates
   }
-  else if (mhd_SOCKET_ERR_IS_HARD(res))
+  else if (mhd_SOCKET_ERR_IS_HARD (res))
   {
     c->sk_discnt_err = res;
     c->sk_ready =
diff --git a/src/mhd2/conn_data_send.h b/src/mhd2/conn_data_send.h
index d3d88190..bce642a6 100644
--- a/src/mhd2/conn_data_send.h
+++ b/src/mhd2/conn_data_send.h
@@ -42,7 +42,7 @@ struct MHD_Connection; /* forward declarations */
  *        type is performed
  */
 MHD_INTERNAL void
-mhd_conn_data_send (struct MHD_Connection restrict *c,
+mhd_conn_data_send (struct MHD_Connection *restrict c,
                     bool has_err)
 MHD_FN_PAR_NONNULL_ALL_;
 
diff --git a/src/mhd2/daemon_add_conn.c b/src/mhd2/daemon_add_conn.c
index 22a0a592..21c3d241 100644
--- a/src/mhd2/daemon_add_conn.c
+++ b/src/mhd2/daemon_add_conn.c
@@ -99,7 +99,7 @@ connection_set_initial_state (struct MHD_Connection *restrict 
c)
   c->read_buffer_offset = 0;
   read_buf_size = c->daemon->conns.cfg.mem_pool_size / 2;
   c->read_buffer
-    = MHD_pool_allocate (c->pool,
+    = mhd_pool_allocate (c->pool,
                          read_buf_size,
                          false);
   c->read_buffer_size = read_buf_size;
@@ -131,7 +131,7 @@ connection_clean_destroy (struct MHD_Connection *restrict c,
 
   // TODO: upgrade support
 
-  MHD_pool_destroy (c->pool);
+  mhd_pool_destroy (c->pool);
 
   // TODO: TLS deinit
 
@@ -314,7 +314,7 @@ new_connection_process_ (struct MHD_Daemon *restrict daemon,
    * intensively used memory area is allocated in "good"
    * (for the thread) memory region. It is important with
    * NUMA and/or complex cache hierarchy. */
-  connection->pool = MHD_pool_create (daemon->conns.cfg.mem_pool_size);
+  connection->pool = mdh_pool_create (daemon->conns.cfg.mem_pool_size);
   if (NULL == connection->pool)
   { /* 'pool' creation failed */
     MHD_LOG_MSG (daemon, MHD_SC_POOL_MALLOC_FAILURE, \
@@ -430,7 +430,7 @@ new_connection_process_ (struct MHD_Daemon *restrict daemon,
       daemon->conns.count--;
       daemon->conns.block_new = false;
     }
-    MHD_pool_destroy (connection->pool);
+    mhd_pool_destroy (connection->pool);
   }
   /* Free resources allocated before the call of this functions */
 
diff --git a/src/mhd2/daemon_add_conn.h b/src/mhd2/daemon_add_conn.h
index 3238d02f..dacac27a 100644
--- a/src/mhd2/daemon_add_conn.h
+++ b/src/mhd2/daemon_add_conn.h
@@ -35,6 +35,7 @@
 #include "sys_bool_type.h"
 
 struct MHD_Daemon; /* Forward declaration */
+struct MHD_Connection; /* Forward declaration */
 
 /**
  * The result of the accepting of the new connection
@@ -79,5 +80,15 @@ enum mhd_DaemonAcceptResult
 MHD_INTERNAL enum mhd_DaemonAcceptResult
 mhd_daemon_accept_connection (struct MHD_Daemon *restrict daemon);
 
+/**
+ * Finally close and clean-up connection.
+ * Must be performed only when connection thread (for thread-per-connection)
+ * has stopped.
+ * @param c the connection to close
+ */
+MHD_INTERNAL void
+mhd_conn_close_final (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
 
 #endif /* ! MHD_DAEMON_ADD_CONN */
diff --git a/src/mhd2/daemon_funcs.c b/src/mhd2/daemon_funcs.c
index 6640ef43..ae6e6f74 100644
--- a/src/mhd2/daemon_funcs.c
+++ b/src/mhd2/daemon_funcs.c
@@ -26,14 +26,31 @@
 
 #include "mhd_sys_options.h"
 
-#ifdef MHD_USE_THREADS
-
 #include "daemon_funcs.h"
 
+#include "sys_base_types.h"
+#include "sys_malloc.h"
+
+#include "mhd_assert.h"
 #include "mhd_itc.h"
 #include "mhd_daemon.h"
 #include "daemon_logger.h"
 
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_MUST_CHECK_RESULT_ struct MHD_Daemon *
+mhd_daemon_get_master_daemon (struct MHD_Daemon *restrict d)
+{
+#ifdef MHD_USE_THREADS
+  if (mhd_D_TYPE_HAS_MASTER_DAEMON (d->threading.d_type))
+    return d->threading.hier.master;
+#endif /* MHD_USE_THREADS */
+  return d;
+}
+
+
+#ifdef MHD_USE_THREADS
+
 MHD_INTERNAL bool
 mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d)
 {
@@ -49,3 +66,117 @@ mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d)
 
 
 #endif /* MHD_USE_THREADS */
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_daemon_resume_conns (struct MHD_Daemon *restrict d)
+{
+  (void) d;
+  mhd_assert (0 && "Not implemented yet");
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_MUST_CHECK_RESULT_ bool
+mhd_daemon_claim_lbuf (struct MHD_Daemon *d,
+                       size_t requested_size)
+{
+  bool ret;
+  struct MHD_Daemon *const masterd = mhd_daemon_get_master_daemon (d);
+  mhd_assert (0 != requested_size);
+  if (0 == masterd->req_cfg.large_buf.space_left)
+    return false; /* Shortcut for typical use without large buffer */
+
+  ret = false;
+  mhd_mutex_lock_chk (&(masterd->req_cfg.large_buf.lock));
+  if (masterd->req_cfg.large_buf.space_left >= requested_size)
+  {
+    masterd->req_cfg.large_buf.space_left -= requested_size;
+    ret = true;
+  }
+  mhd_mutex_unlock_chk (&(masterd->req_cfg.large_buf.lock));
+  return ret;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_daemon_reclaim_lbuf (struct MHD_Daemon *d,
+                         size_t reclaimed_size)
+{
+  struct MHD_Daemon *const masterd = mhd_daemon_get_master_daemon (d);
+  mhd_assert (0 != reclaimed_size);
+  mhd_mutex_lock_chk (&(masterd->req_cfg.large_buf.lock));
+  masterd->req_cfg.large_buf.space_left += reclaimed_size;
+  mhd_mutex_unlock_chk (&(masterd->req_cfg.large_buf.lock));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+MHD_FN_PAR_OUT_ (3) bool
+mhd_daemon_get_lbuf (struct MHD_Daemon *restrict d,
+                     size_t requested_size,
+                     struct mhd_Buffer *restrict buf)
+{
+  if (! mhd_daemon_claim_lbuf (d, requested_size))
+  {
+    buf->size = 0;
+    buf->buf = NULL;
+    return false;
+  }
+  buf->buf = (char *) malloc (requested_size);
+  if (NULL == buf->buf)
+  {
+    buf->size = 0;
+    mhd_daemon_reclaim_lbuf (d, requested_size);
+    return false;
+  }
+  buf->size = requested_size;
+  return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+MHD_FN_PAR_INOUT_ (3) bool
+mhd_daemon_grow_lbuf (struct MHD_Daemon *restrict d,
+                      size_t grow_size,
+                      struct mhd_Buffer *restrict buf)
+{
+  void *new_alloc;
+  mhd_assert (NULL != buf->buf || 0 == buf->size);
+  mhd_assert (0 != buf->size || NULL == buf->buf);
+
+  if (! mhd_daemon_claim_lbuf (d, grow_size))
+    return false;
+
+  if (NULL == buf->buf)
+    new_alloc = malloc (grow_size);
+  else
+    new_alloc = realloc (buf->buf, buf->size + grow_size);
+  if (NULL == new_alloc)
+  {
+    mhd_daemon_reclaim_lbuf (d, grow_size);
+    return false;
+  }
+
+  buf->buf = (char *) new_alloc;
+  buf->size += grow_size;
+
+  return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_INOUT_ (2) void
+mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
+                      struct mhd_Buffer *restrict buf)
+{
+  if (0 == buf->size)
+  {
+    mhd_assert (NULL == buf->buf);
+    return;
+  }
+  free (buf->buf);
+  buf->buf = NULL;
+  mhd_daemon_reclaim_lbuf (d, buf->size);
+  buf->size = 0;
+}
diff --git a/src/mhd2/daemon_funcs.h b/src/mhd2/daemon_funcs.h
index e5acd8aa..73cc3a79 100644
--- a/src/mhd2/daemon_funcs.h
+++ b/src/mhd2/daemon_funcs.h
@@ -29,13 +29,24 @@
 
 #include "mhd_sys_options.h"
 
-#ifdef MHD_USE_THREADS
-
 #include "sys_bool_type.h"
 
+#include "mhd_buffer.h"
+
 struct MHD_Daemon; /* forward declaration */
 
 
+/**
+ * Get controlling daemon
+ * @param d the daemon to get controlling daemon
+ * @return the master daemon (possible the same as the @a d)
+ */
+MHD_INTERNAL struct MHD_Daemon *
+mhd_daemon_get_master_daemon (struct MHD_Daemon *restrict d)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
+
+#ifdef MHD_USE_THREADS
+
 /**
  * Trigger daemon ITC.
  * This should cause daemon's thread to stop waiting for the network events
@@ -46,6 +57,7 @@ struct MHD_Daemon; /* forward declaration */
 MHD_INTERNAL bool
 mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d);
 
+#endif /* MHD_USE_THREADS */
 
 
 /**
@@ -54,8 +66,73 @@ mhd_daemon_trigger_itc (struct MHD_Daemon *restrict d);
  */
 MHD_INTERNAL void
 mhd_daemon_resume_conns (struct MHD_Daemon *restrict d)
-MHD_FN_PAR_NONNULL_ALL_ ;
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Request allocation of the large buffer
+ * @param d the daemon to use
+ * @param requested_size the requested size of allocation
+ * @return true if allocation allowed and counted,
+ *         false otherwise
+ */
+MHD_INTERNAL bool
+mhd_daemon_claim_lbuf (struct MHD_Daemon *restrict d,
+                       size_t requested_size)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
+
+
+/**
+ * Reclaim the large buffer allocation.
+ * Must be called when the allocation has been already freed.
+ * @param d the daemon to use
+ * @param reclaimed_size the deallocated size
+ */
+MHD_INTERNAL void
+mhd_daemon_reclaim_lbuf (struct MHD_Daemon *restrict d,
+                         size_t reclaimed_size)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Allocate the large buffer
+ * @param d the daemon to use
+ * @param requested_size the requested size of allocation
+ * @param[out] buf the buffer to allocate
+ * @return true if buffer is allocated,
+ *         false otherwise
+ */
+MHD_INTERNAL bool
+mhd_daemon_get_lbuf (struct MHD_Daemon *restrict d,
+                     size_t requested_size,
+                     struct mhd_Buffer *restrict buf)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+  MHD_FN_PAR_OUT_ (3);
+
+/**
+ * Grow the large buffer, which previously was allocated
+ * @param d the daemon to use
+ * @param grow_size the requested size of grow
+ * @param[in,out] buf the buffer to grow
+ * @return true if buffer has been grown,
+ *         false otherwise
+ */
+MHD_INTERNAL bool
+mhd_daemon_grow_lbuf (struct MHD_Daemon *restrict d,
+                      size_t grow_size,
+                      struct mhd_Buffer *restrict buf)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+  MHD_FN_PAR_INOUT_ (3);
+
+
+/**
+ * Free large buffer.
+ * @param d the daemon to use
+ * @param[in,out] buf the buffer to free
+ */
+MHD_INTERNAL void
+mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
+                      struct mhd_Buffer *restrict buf)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (2);
 
-#endif /* MHD_USE_THREADS */
 
 #endif /* ! MHD_DAEMON_FUNCS_H */
diff --git a/src/mhd2/daemon_options.h b/src/mhd2/daemon_options.h
index 5cad1b28..973f5ab4 100644
--- a/src/mhd2/daemon_options.h
+++ b/src/mhd2/daemon_options.h
@@ -137,6 +137,12 @@ struct DaemonOptions {
   unsigned int global_connection_limit;
 
 
+  /**
+   * // TODO: add settings
+   */
+  size_t global_large_buffer_size;
+
+
   /**
    * Value for #MHD_D_O_PER_IP_LIMIT.
    * FIXME
diff --git a/src/mhd2/daemon_start.c b/src/mhd2/daemon_start.c
index 52aa11e3..e98e0c2a 100644
--- a/src/mhd2/daemon_start.c
+++ b/src/mhd2/daemon_start.c
@@ -107,8 +107,8 @@ dsettings_release (struct DaemonOptions *s)
  * @return MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 daemon_set_work_mode (struct MHD_Daemon *restrict d,
                       struct DaemonOptions *restrict s)
 {
@@ -982,7 +982,7 @@ create_bind_listen_stream_socket (struct MHD_Daemon 
*restrict d,
  * Detect and set the type and port of the listening socket
  * @param d the daemon to use
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 detect_listen_type_and_port (struct MHD_Daemon *restrict d)
 {
   union mhd_SockaddrAny sa_all;
@@ -1053,7 +1053,7 @@ detect_listen_type_and_port (struct MHD_Daemon *restrict 
d)
 /**
  * Initialise daemon's epoll FD
  */
-MHD_FN_PAR_NONNULL_ (1) static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) enum MHD_StatusCode
 init_epoll (struct MHD_Daemon *restrict d)
 {
   int e_fd;
@@ -1129,8 +1129,8 @@ deinit_epoll (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+  MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 daemon_choose_and_preinit_events (struct MHD_Daemon *restrict d,
                                   struct DaemonOptions *restrict s)
 {
@@ -1318,8 +1318,8 @@ daemon_choose_and_preinit_events (struct MHD_Daemon 
*restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+  MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 daemon_init_net (struct MHD_Daemon *restrict d,
                  struct DaemonOptions *restrict s)
 {
@@ -1433,6 +1433,42 @@ dauth_init (struct MHD_Daemon *restrict d,
 
 #endif
 
+/**
+ * Initialise large buffer tracking.
+ * @param d the daemon object
+ * @param s the user settings
+ * @return #MHD_SC_OK on success,
+ *         the error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+  MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_large_buf (struct MHD_Daemon *restrict d,
+                       struct DaemonOptions *restrict s)
+{
+  d->req_cfg.large_buf.space_left = s->global_large_buffer_size;
+  if (! mhd_mutex_init_short (&(d->req_cfg.large_buf.lock)))
+  {
+    MHD_LOG_MSG (d, MHD_SC_MUTEX_INIT_FAILURE, \
+                 "Failed to initialise mutex for the global large buffer.");
+    return MHD_SC_MUTEX_INIT_FAILURE;
+  }
+  return MHD_SC_OK;
+}
+
+
+/**
+ * Initialise large buffer tracking.
+ * @param d the daemon object
+ * @param s the user settings
+ * @return #MHD_SC_OK on success,
+ *         the error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) void
+daemon_deinit_large_buf (struct MHD_Daemon *restrict d)
+{
+  mhd_mutex_destroy_chk (&(d->req_cfg.large_buf.lock));
+}
+
 
 /**
  * Finish initialisation of events processing
@@ -1440,8 +1476,8 @@ dauth_init (struct MHD_Daemon *restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 allocate_events (struct MHD_Daemon *restrict d)
 {
   mhd_assert (0 != d->conns.cfg.count_limit);
@@ -1586,7 +1622,7 @@ allocate_events (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 deallocate_events (struct MHD_Daemon *restrict d)
 {
   mhd_assert (0 != d->conns.cfg.count_limit);
@@ -1638,8 +1674,8 @@ deallocate_events (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 init_itc (struct MHD_Daemon *restrict d)
 {
   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
@@ -1679,7 +1715,7 @@ init_itc (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 deinit_itc (struct MHD_Daemon *restrict d)
 {
   mhd_assert (mhd_D_TYPE_IS_VALID (d->threading.d_type));
@@ -1699,8 +1735,8 @@ deinit_itc (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 add_itc_and_listen_to_monitoring (struct MHD_Daemon *restrict d)
 {
   mhd_assert (d->dbg.net_inited);
@@ -1813,8 +1849,8 @@ add_itc_and_listen_to_monitoring (struct MHD_Daemon 
*restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 init_individual_conns (struct MHD_Daemon *restrict d,
                        struct DaemonOptions *restrict s)
 {
@@ -1849,8 +1885,8 @@ init_individual_conns (struct MHD_Daemon *restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 init_individual_thread_data_events_conns (struct MHD_Daemon *restrict d,
                                           struct DaemonOptions *restrict s)
 {
@@ -1903,7 +1939,7 @@ init_individual_thread_data_events_conns (struct 
MHD_Daemon *restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 deinit_individual_thread_data_events_conns (struct MHD_Daemon *restrict d)
 {
   deinit_itc (d);
@@ -1924,8 +1960,8 @@ deinit_individual_thread_data_events_conns (struct 
MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 set_connections_total_limits (struct MHD_Daemon *restrict d,
                               struct DaemonOptions *restrict s)
 {
@@ -2157,7 +2193,7 @@ set_d_threading_type (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 deinit_workers_pool (struct MHD_Daemon *restrict d,
                      unsigned int num_workers)
 {
@@ -2188,6 +2224,17 @@ deinit_workers_pool (struct MHD_Daemon *restrict d,
 }
 
 
+/**
+ * Nullify worker daemon member that should be set only in master daemon
+ * @param d
+ */
+static MHD_FN_PAR_NONNULL_ (1) void
+reset_master_only_areas (struct MHD_Daemon *restrict d)
+{
+  memset (&(d->req_cfg.large_buf), 0, sizeof(d->req_cfg.large_buf));
+}
+
+
 /**
  * Initialise workers pool, including workers daemons.
  * Do not start the threads.
@@ -2196,8 +2243,8 @@ deinit_workers_pool (struct MHD_Daemon *restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 init_workers_pool (struct MHD_Daemon *restrict d,
                    struct DaemonOptions *restrict s)
 {
@@ -2252,6 +2299,8 @@ init_workers_pool (struct MHD_Daemon *restrict d,
     struct MHD_Daemon *restrict const worker =
       d->threading.hier.pool.workers + i;
     memcpy (worker, d, sizeof(struct MHD_Daemon));
+    reset_master_only_areas (d);
+
     worker->threading.d_type = mhd_DAEMON_TYPE_WORKER;
     worker->threading.hier.master = d;
     worker->conns.cfg.count_limit = conn_per_daemon;
@@ -2318,8 +2367,8 @@ init_workers_pool (struct MHD_Daemon *restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
-  MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 daemon_init_threading_and_conn (struct MHD_Daemon *restrict d,
                                 struct DaemonOptions *restrict s)
 {
@@ -2375,7 +2424,7 @@ daemon_init_threading_and_conn (struct MHD_Daemon 
*restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 daemon_deinit_threading_and_conn (struct MHD_Daemon *restrict d)
 {
   mhd_assert (d->dbg.net_inited);
@@ -2418,8 +2467,8 @@ daemon_deinit_threading_and_conn (struct MHD_Daemon 
*restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 start_individual_daemon_thread (struct MHD_Daemon *restrict d)
 {
   mhd_assert (d->dbg.threading_inited);
@@ -2513,7 +2562,7 @@ stop_individual_daemon_thread (struct MHD_Daemon 
*restrict d)
  * @param d the daemon object, the workers threads must be running
  * @param num_workers the number of threads to stop
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 stop_worker_pool_threads (struct MHD_Daemon *restrict d,
                           unsigned int num_workers)
 {
@@ -2560,8 +2609,8 @@ stop_worker_pool_threads (struct MHD_Daemon *restrict d,
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 start_worker_pool_threads (struct MHD_Daemon *restrict d)
 {
   enum MHD_StatusCode res;
@@ -2602,8 +2651,8 @@ start_worker_pool_threads (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 daemon_start_threads (struct MHD_Daemon *restrict d)
 {
   mhd_assert (d->dbg.net_inited);
@@ -2641,7 +2690,7 @@ daemon_start_threads (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) static void
+static MHD_FN_PAR_NONNULL_ (1) void
 daemon_stop_threads (struct MHD_Daemon *restrict d)
 {
   mhd_assert (d->dbg.net_inited);
@@ -2681,8 +2730,8 @@ daemon_stop_threads (struct MHD_Daemon *restrict d)
  * @return #MHD_SC_OK on success,
  *         the error code otherwise
  */
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
-MHD_FN_MUST_CHECK_RESULT_ static enum MHD_StatusCode
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2)
+MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 daemon_start_internal (struct MHD_Daemon *restrict d,
                        struct DaemonOptions *restrict s)
 {
@@ -2696,33 +2745,38 @@ daemon_start_internal (struct MHD_Daemon *restrict d,
   if (MHD_SC_OK != res)
     return res;
 
-  // TODO: Other init
-
-  res = daemon_init_threading_and_conn (d, s);
+  res = daemon_init_large_buf (d, s);
   if (MHD_SC_OK == res)
   {
-    mhd_assert (d->dbg.net_inited);
-    mhd_assert (d->dbg.threading_inited);
-    mhd_assert (! mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
 
-    res = daemon_start_threads (d);
+    // TODO: Other init
+
+    res = daemon_init_threading_and_conn (d, s);
     if (MHD_SC_OK == res)
     {
-      return MHD_SC_OK;
-    }
+      mhd_assert (d->dbg.net_inited);
+      mhd_assert (d->dbg.threading_inited);
+      mhd_assert (! mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
 
-    /* Below is a clean-up path */
-    daemon_deinit_threading_and_conn (d);
-  }
+      res = daemon_start_threads (d);
+      if (MHD_SC_OK == res)
+      {
+        return MHD_SC_OK;
+      }
 
+      /* Below is a clean-up path */
+      daemon_deinit_threading_and_conn (d);
+    }
+    daemon_deinit_large_buf (d);
+  }
   daemon_deinit_net (d);
   mhd_assert (MHD_SC_OK != res);
   return res;
 }
 
 
-MHD_FN_PAR_NONNULL_ (1) MHD_FN_MUST_CHECK_RESULT_ \
-  MHD_EXTERN_ enum MHD_StatusCode
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
 MHD_daemon_start (struct MHD_Daemon *daemon)
 {
   struct MHD_Daemon *const d = daemon; /* a short alias */
@@ -2747,7 +2801,7 @@ MHD_daemon_start (struct MHD_Daemon *daemon)
 }
 
 
-MHD_FN_PAR_NONNULL_ALL_ MHD_EXTERN_ void
+MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ void
 MHD_daemon_destroy (struct MHD_Daemon *daemon)
 {
   bool not_yet_started = (mhd_DAEMON_STATE_NOT_STARTED == daemon->state);
@@ -2771,6 +2825,8 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon)
 
     daemon_deinit_threading_and_conn (daemon);
 
+    daemon_deinit_large_buf (daemon);
+
     daemon_deinit_net (daemon);
   }
   daemon->state = mhd_DAEMON_STATE_STOPPED; /* Useful only for debugging */
diff --git a/src/mhd2/http_prot_ver.h b/src/mhd2/http_prot_ver.h
index 70cac271..b9a3ce29 100644
--- a/src/mhd2/http_prot_ver.h
+++ b/src/mhd2/http_prot_ver.h
@@ -55,4 +55,17 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_HTTP_ProtocolVersion
 #define MHD_HTTP_PROTOCOL_VER_DEFINED 1
 #endif /* ! MHD_HTTP_PROTOCOL_VER_DEFINED */
 
+/**
+ * Check whether version of HTTP protocol is supported
+ */
+#define MHD_HTTP_VERSION_IS_SUPPORTED(v) \
+        ((MHD_HTTP_VERSION_1_0 <= (v)) && (MHD_HTTP_VERSION_1_1 >= (v)))
+
+/**
+ * Check whether version of HTTP protocol is valid
+ */
+#define MHD_HTTP_VERSION_IS_VALID(v) \
+        (((MHD_HTTP_VERSION_1_0 <= (v)) && (MHD_HTTP_VERSION_3 >= (v))) || \
+         (MHD_HTTP_VERSION_FUTURE == (v)))
+
 #endif /* ! MHD_HTTP_PROT_VER_H */
diff --git a/src/mhd2/http_status_str.c b/src/mhd2/http_status_str.c
index d946ff03..5d5154cc 100644
--- a/src/mhd2/http_status_str.c
+++ b/src/mhd2/http_status_str.c
@@ -27,6 +27,8 @@
  */
 #include "mhd_sys_options.h"
 
+#include "http_status_str.h"
+
 #include "sys_base_types.h"
 #include "mhd_public_api.h"
 #include "mhd_str_macros.h"
@@ -177,7 +179,7 @@ static const struct mhd_HttpStatusesBlock statuses[] = {
 MHD_EXTERN_ MHD_FN_CONST_ const struct MHD_String *
 MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode code)
 {
-  struct MHD_String *res;
+  const struct MHD_String *res;
   const unsigned int code_i = (unsigned int) code;
   if (100 > code_i)
     return NULL;
@@ -185,7 +187,7 @@ MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode 
code)
     return NULL;
   if (statuses[code_i / 100].max > (code_i % 100))
     return NULL;
-  res = statuses[code_i / 100] + (code_i % 100);
+  res = statuses[code_i / 100].data + (code_i % 100);
   if (NULL == res->cstr)
     return NULL;
   return res;
@@ -193,13 +195,13 @@ MHD_HTTP_status_code_to_string (enum MHD_HTTP_StatusCode 
code)
 
 
 MHD_INTERNAL MHD_FN_CONST_ const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
+mhd_HTTP_status_code_to_string_int (unsigned int code)
 {
   static const struct MHD_String no_status =
     mhd_MSTR_INIT ("Nonstandard Status");
   const struct MHD_String *res;
 
-  res = MHD_status_code_to_string (code);
+  res = MHD_HTTP_status_code_to_string ((enum MHD_HTTP_StatusCode) code);
   if (NULL != res)
     return res;
 
diff --git a/src/mhd2/http_status_str.h b/src/mhd2/http_status_str.h
index 4906943b..3eef398e 100644
--- a/src/mhd2/http_status_str.h
+++ b/src/mhd2/http_status_str.h
@@ -39,7 +39,7 @@
  * @return pointer to MHD_String, never NULL.
  */
 MHD_INTERNAL const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
+mhd_HTTP_status_code_to_string_int (unsigned int code)
 MHD_FN_CONST_;
 
 
diff --git a/src/mhd2/mhd_action.h b/src/mhd2/mhd_action.h
index a56fbf32..25289710 100644
--- a/src/mhd2/mhd_action.h
+++ b/src/mhd2/mhd_action.h
@@ -33,6 +33,7 @@
 
 #include "mhd_str_types.h"
 
+
 /**
  * The type of the action requested by application
  */
@@ -49,29 +50,35 @@ enum mhd_ActionType
   mhd_ACTION_RESPONSE
   ,
   /**
-   * Suspend requests (connection)
+   * Process clients upload by application callback
    */
-  mhd_ACTION_SUSPEND
+  mhd_ACTION_UPLOAD
   ,
   /**
-   * Hard close request with no response
+   * Process clients upload by POST processor
    */
-  mhd_ACTION_CLOSE
+  mhd_ACTION_POST_PROCESS
   ,
   /**
-   * Process clients upload by application callback
+   * Suspend requests (connection)
    */
-  mhd_ACTION_UPLOAD
+  mhd_ACTION_SUSPEND
   ,
   /**
-   * Process clients upload by POST processor
+   * Hard close request with no response
    */
-  mhd_ACTION_POST_PROCESS
+  mhd_ACTION_ABORT
 };
 
+/**
+ * Check whether provided mhd_ActionType value is valid
+ */
+#define mhd_ACTION_IS_VALID(act) \
+        ((mhd_ACTION_RESPONSE <= (act)) && (mhd_ACTION_ABORT >= (act)))
 
-struct MHD_Response; /* forward declaration */
 
+struct MHD_Response; /* forward declaration */
+struct MHD_Request;  /* forward declaration */
 
 #ifndef MHD_UPLOADCALLBACK_DEFINED
 
@@ -242,6 +249,11 @@ enum mhd_UploadActionType
    */
   mhd_UPLOAD_ACTION_NO_ACTION = 0
   ,
+  /**
+   * Continue processing the upload
+   */
+  mhd_UPLOAD_ACTION_CONTINUE
+  ,
   /**
    * Start replying with the response
    */
@@ -255,14 +267,17 @@ enum mhd_UploadActionType
   /**
    * Hard close request with no response
    */
-  mhd_UPLOAD_ACTION_CLOSE
-  ,
-  /**
-   * Continue processing the upload
-   */
-  mhd_UPLOAD_ACTION_CONTINUE
+  mhd_UPLOAD_ACTION_ABORT
 };
 
+/**
+ * Check whether provided mhd_UploadActionType value is valid
+ */
+#define mhd_UPLOAD_ACTION_IS_VALID(act) \
+        ((mhd_UPLOAD_ACTION_CONTINUE <= (act)) && \
+         (mhd_UPLOAD_ACTION_ABORT >= (act)))
+
+
 /**
  * The data for the application action
  */
diff --git a/src/mhd2/mhd_atomic_counter.c b/src/mhd2/mhd_atomic_counter.c
index c6edc896..02fb93d7 100644
--- a/src/mhd2/mhd_atomic_counter.c
+++ b/src/mhd2/mhd_atomic_counter.c
@@ -30,44 +30,49 @@
 
 #if defined(mhd_ATOMIC_BY_LOCKS)
 
+#include "mhd_assert.h"
+
 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
 mhd_atomic_counter_inc_get (struct mhd_AtomicCounter *pcnt)
 {
   mhd_ATOMIC_COUNTER_TYPE ret;
 
-  mhd_mutex_lock_chk(&(pcnt->lock));
+  mhd_mutex_lock_chk (&(pcnt->lock));
   ret = ++(pcnt->count);
-  mhd_mutex_unlock_chk(&(pcnt->lock));
+  mhd_mutex_unlock_chk (&(pcnt->lock));
 
   mhd_assert (0 != ret); /* check for overflow */
 
   return ret;
 }
 
+
 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
 mhd_atomic_counter_dec_get (struct mhd_AtomicCounter *pcnt)
 {
   mhd_ATOMIC_COUNTER_TYPE ret;
 
-  mhd_mutex_lock_chk(&(pcnt->lock));
+  mhd_mutex_lock_chk (&(pcnt->lock));
   ret = --(pcnt->count);
-  mhd_mutex_unlock_chk(&(pcnt->lock));
+  mhd_mutex_unlock_chk (&(pcnt->lock));
 
   mhd_assert (mhd_ATOMIC_COUNTER_MAX != ret); /* check for underflow */
 
   return ret;
 }
 
+
 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
 mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt)
 {
   mhd_ATOMIC_COUNTER_TYPE ret;
 
-  mhd_mutex_lock_chk(&(pcnt->lock));
+  mhd_mutex_lock_chk (&(pcnt->lock));
   ret = pcnt->count;
-  mhd_mutex_unlock_chk(&(pcnt->lock));
+  mhd_mutex_unlock_chk (&(pcnt->lock));
 
   return ret;
 }
 
+
 #endif /* mhd_ATOMIC_BY_LOCKS */
diff --git a/src/mhd2/mhd_atomic_counter.h b/src/mhd2/mhd_atomic_counter.h
index 2410a3e5..d42962ad 100644
--- a/src/mhd2/mhd_atomic_counter.h
+++ b/src/mhd2/mhd_atomic_counter.h
@@ -44,7 +44,7 @@
  * The maximum counter value
  */
 #define mhd_ATOMIC_COUNTER_MAX \
-  ((mhd_ATOMIC_COUNTER_TYPE)(~((mhd_ATOMIC_COUNTER_TYPE)0)))
+        ((mhd_ATOMIC_COUNTER_TYPE) (~((mhd_ATOMIC_COUNTER_TYPE) 0)))
 
 #ifdef MHD_USE_THREADS
 
@@ -109,23 +109,25 @@ struct mhd_AtomicCounter
  *          already.
  */
 #  define mhd_atomic_counter_init(pcnt,initial_value) \
-  ((pcnt)->count=(initial_value), mhd_mutex_init_short(&(pcnt->lock)))
+        ((pcnt)->count = (initial_value), \
+         mhd_mutex_init_short (&((pcnt)->lock)))
 
 /**
  * Deinitialise the counter.
  * @param pcnt the pointer to the counter to deinitialise
  * @warning Must be called only for the counters that has been initialised.
  */
-#  define mhd_atomic_counter_deinit(pcnt) 
mhd_mutex_destroy_chk(&((pcnt)->lock))
+#  define mhd_atomic_counter_deinit(pcnt) \
+        mhd_mutex_destroy_chk (&((pcnt)->lock))
 
 /**
  * Atomically increment the value of the counter
  * @param pcnt the pointer to the counter to increment
  */
 #  define mhd_atomic_counter_inc(pcnt)  do { \
-      mhd_mutex_lock_chk(&(pcnt->lock));     \
-      ++(pcnt->count);                       \
-      mhd_mutex_unlock_chk(&(pcnt->lock)); } while (0)
+          mhd_mutex_lock_chk (&((pcnt)->lock));     \
+          ++(pcnt->count);                       \
+          mhd_mutex_unlock_chk (&((pcnt)->lock)); } while (0)
 
 /**
  * Atomically increment the value of the counter and return the result
@@ -162,14 +164,14 @@ mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt);
  *          already.
  */
 #  define mhd_atomic_counter_init(pcnt,initial_value) \
-  ((pcnt)->count=(initial_value), (! 0))
+        ((pcnt)->count = (initial_value), (! 0))
 
 /**
  * Deinitialise the counter.
  * @param pcnt the pointer to the counter to deinitialise
  * @warning Must be called only for the counters that has been initialised.
  */
-#  define mhd_atomic_counter_deinit(pcnt) ((void)0)
+#  define mhd_atomic_counter_deinit(pcnt) ((void) 0)
 
 /**
  * Atomically increment the value of the counter
diff --git a/src/mhd2/http_status_str.h b/src/mhd2/mhd_buffer.h
similarity index 63%
copy from src/mhd2/http_status_str.h
copy to src/mhd2/mhd_buffer.h
index 4906943b..1e282b2c 100644
--- a/src/mhd2/http_status_str.h
+++ b/src/mhd2/mhd_buffer.h
@@ -19,28 +19,31 @@
 */
 
 /**
- * @file src/mhd2/http_status_str.h
- * @brief  The declaration for internal HTTP status string functions
+ * @file src/mhd2/mhd_buffer.h
+ * @brief  The definition of the MHD_Buffer type
  * @author Karlson2k (Evgeny Grin)
  */
 
-#ifndef MHD_HTTP_STATUS_STR_H
-#define MHD_HTTP_STATUS_STR_H 1
+#ifndef MHD_BUFFER_H
+#define MHD_BUFFER_H 1
 
 #include "mhd_sys_options.h"
-
-#include "mhd_str_types.h"
+#include "sys_base_types.h"
 
 /**
- * Get string for provided HTTP status code.
- * Substitute a replacement string for unknown codes.
- *
- * @param code the HTTP status code
- * @return pointer to MHD_String, never NULL.
+ * The buffer with size
  */
-MHD_INTERNAL const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
-MHD_FN_CONST_;
-
-
-#endif /* ! MHD_HTTP_STATUS_STR_H */
+struct mhd_Buffer
+{
+  /**
+   * The size of the allocated @a buf buffer
+   */
+  size_t size;
+
+  /**
+   * The pointer to the allocation
+   */
+  char *buf;
+};
+
+#endif /* ! MHD_BUFFER_H */
diff --git a/src/mhd2/mhd_connection.h b/src/mhd2/mhd_connection.h
index 19978980..45fdf92c 100644
--- a/src/mhd2/mhd_connection.h
+++ b/src/mhd2/mhd_connection.h
@@ -207,124 +207,131 @@ enum MHD_FIXED_ENUM_ MHD_CONNECTION_STATE
    * Part of the request line was received.
    * Wait for complete line.
    */
-  MHD_CONNECTION_REQ_LINE_RECEIVING = MHD_CONNECTION_INIT + 1,
+  MHD_CONNECTION_REQ_LINE_RECEIVING,
 
   /**
    * We got the URL (and request type and version).  Wait for a header line.
    *
    * A milestone state. No received data is processed in this state.
    */
-  MHD_CONNECTION_REQ_LINE_RECEIVED = MHD_CONNECTION_REQ_LINE_RECEIVING + 1,
+  MHD_CONNECTION_REQ_LINE_RECEIVED,
 
   /**
    * Receiving request headers.  Wait for the rest of the headers.
    */
-  MHD_CONNECTION_REQ_HEADERS_RECEIVING = MHD_CONNECTION_REQ_LINE_RECEIVED + 1,
+  MHD_CONNECTION_REQ_HEADERS_RECEIVING,
 
   /**
    * We got the request headers.  Process them.
    */
-  MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_REQ_HEADERS_RECEIVING + 1,
+  MHD_CONNECTION_HEADERS_RECEIVED,
 
   /**
    * We have processed the request headers.  Call application callback.
    */
-  MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
+  MHD_CONNECTION_HEADERS_PROCESSED,
 
   /**
    * We have processed the headers and need to send 100 CONTINUE.
    */
-  MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
+  MHD_CONNECTION_CONTINUE_SENDING,
 
   /**
    * We have sent 100 CONTINUE (or do not need to).  Read the message body.
    */
-  MHD_CONNECTION_BODY_RECEIVING = MHD_CONNECTION_CONTINUE_SENDING + 1,
+  MHD_CONNECTION_BODY_RECEIVING,
 
   /**
    * We got the request body.
    *
    * A milestone state. No received data is processed in this state.
    */
-  MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_BODY_RECEIVING + 1,
+  MHD_CONNECTION_BODY_RECEIVED,
 
   /**
    * We are reading the request footers.
    */
-  MHD_CONNECTION_FOOTERS_RECEIVING = MHD_CONNECTION_BODY_RECEIVED + 1,
+  MHD_CONNECTION_FOOTERS_RECEIVING,
 
   /**
    * We received the entire footer.
    *
-   * A milestone state. No received data is processed in this state.
+   * A milestone state. No data is receiving in this state.
    */
-  MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTERS_RECEIVING + 1,
+  MHD_CONNECTION_FOOTERS_RECEIVED,
 
   /**
    * We received the entire request.
-   * Wait for a response to be queued.
+   *
+   * A milestone state. No data is receiving in this state.
+   */
+  MHD_CONNECTION_FULL_REQ_RECEIVED,
+
+  /**
+   * Finished receiving request data: either complete request received or
+   * MHD is going to send reply early, without getting full request.
    */
-  MHD_CONNECTION_FULL_REQ_RECEIVED = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
+  MHD_CONNECTION_REQ_RECV_FINISHED,
 
   /**
    * Finished reading of the request and the response is ready.
    * Switch internal logic from receiving to sending, prepare connection
    * sending the reply and build the reply header.
    */
-  MHD_CONNECTION_START_REPLY = MHD_CONNECTION_FULL_REQ_RECEIVED + 1,
+  MHD_CONNECTION_START_REPLY,
 
   /**
    * We have prepared the response headers in the write buffer.
    * Send the response headers.
    */
-  MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_START_REPLY + 1,
+  MHD_CONNECTION_HEADERS_SENDING,
 
   /**
    * We have sent the response headers.  Get ready to send the body.
    */
-  MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
+  MHD_CONNECTION_HEADERS_SENT,
 
   /**
    * We are waiting for the client to provide more
    * data of a non-chunked body.
    */
-  MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_HEADERS_SENT + 1,
+  MHD_CONNECTION_NORMAL_BODY_UNREADY,
 
   /**
    * We are ready to send a part of a non-chunked body.  Send it.
    */
-  MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
+  MHD_CONNECTION_NORMAL_BODY_READY,
 
   /**
    * We are waiting for the client to provide a chunk of the body.
    */
-  MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
+  MHD_CONNECTION_CHUNKED_BODY_UNREADY,
 
   /**
    * We are ready to send a chunk.
    */
-  MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
+  MHD_CONNECTION_CHUNKED_BODY_READY,
 
   /**
    * We have sent the chunked response body. Prepare the footers.
    */
-  MHD_CONNECTION_CHUNKED_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
+  MHD_CONNECTION_CHUNKED_BODY_SENT,
 
   /**
    * We have prepared the response footer.  Send it.
    */
-  MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_CHUNKED_BODY_SENT + 1,
+  MHD_CONNECTION_FOOTERS_SENDING,
 
   /**
    * We have sent the entire reply.
    * Shutdown connection or restart processing to get a new request.
    */
-  MHD_CONNECTION_FULL_REPLY_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
+  MHD_CONNECTION_FULL_REPLY_SENT,
 
   /**
    * This connection is to be closed.
    */
-  MHD_CONNECTION_CLOSED = MHD_CONNECTION_FULL_REPLY_SENT + 1
+  MHD_CONNECTION_CLOSED
 
 };
 
@@ -360,7 +367,6 @@ enum MHD_FIXED_ENUM_ MHD_ConnKeepAlive
  */
 mhd_DLINKEDL_LINKS_DEF (MHD_Connection);
 
-
 /**
  * State kept for HTTP network connection.
  */
@@ -431,7 +437,7 @@ struct MHD_Connection
    * response (which maybe shared between connections) and the IP
    * address (which persists across individual requests).
    */
-  struct MemoryPool *pool;
+  struct mhd_MemoryPool *pool;
 
   /**
    * We allow the main application to associate some pointer with the
@@ -551,12 +557,12 @@ struct MHD_Connection
    */
   bool sk_spipe_suppress;
 
-//#ifndef MHD_WINSOCK_SOCKETS // TODO: conditionally use in the code
+// #ifndef MHD_WINSOCK_SOCKETS // TODO: conditionally use in the code
   /**
    * Tracks TCP_CORK / TCP_NOPUSH of the connection socket.
    */
   enum mhd_Tristate sk_corked;
-//#endif
+// #endif
 
   /**
    * Tracks TCP_NODELAY state of the connection socket.
diff --git a/src/mhd2/mhd_daemon.h b/src/mhd2/mhd_daemon.h
index 23f2e062..317a9b9a 100644
--- a/src/mhd2/mhd_daemon.h
+++ b/src/mhd2/mhd_daemon.h
@@ -38,6 +38,7 @@
 #ifdef MHD_USE_THREADS
 #  include "mhd_threads.h"
 #  include "mhd_itc_types.h"
+#  include "mhd_locks.h"
 #endif
 
 #if defined(MHD_USE_SELECT) && defined(MHD_POSIX_SOCKETS)
@@ -769,6 +770,38 @@ struct mhd_DaemonConnections
   struct mhd_DaemonConnectionsSettings cfg;
 };
 
+/**
+ * Early URI callback
+ */
+struct mhd_DaemonRequestUriCB
+{
+  /**
+   * The callback
+   */
+  MHD_EarlyUriLogCallback cb;
+  /**
+   * The callback closure
+   */
+  void *cls;
+};
+
+/**
+ * Shared large buffer data
+ */
+struct mhd_DeamonLargeBuffer
+{
+  /**
+   * The amount of memory left allowed to be allocated for the large buffer
+   */
+  size_t space_left;
+
+#ifdef MHD_USE_THREADS
+  /**
+   * The mutex to change or check the @a space_left value
+   */
+  mhd_mutex lock;
+#endif
+};
 
 /**
  * Settings for requests processing
@@ -790,6 +823,16 @@ struct mhd_DaemonRequestProcessingSettings
    * Protocol strictness enforced by MHD on clients.
    */
   enum MHD_ProtocolStrictLevel strictnees;
+
+  /**
+   * Early URI callback
+   */
+  struct mhd_DaemonRequestUriCB uri_cb; // TODO: set from settings
+
+  /**
+   * Shared large buffer data
+   */
+  struct mhd_DeamonLargeBuffer large_buf; // TODO: set from settings
 };
 
 
diff --git a/src/mhd2/mhd_mempool.c b/src/mhd2/mhd_mempool.c
index 85dc36c3..97d1f07d 100644
--- a/src/mhd2/mhd_mempool.c
+++ b/src/mhd2/mhd_mempool.c
@@ -214,7 +214,7 @@ static size_t MHD_sys_page_size_ = (size_t)
  * Initialise values for memory pools
  */
 void
-MHD_init_mem_pools_ (void)
+mhd_init_mem_pools (void)
 {
 #ifdef MHD_SC_PAGESIZE
   long result;
@@ -238,7 +238,7 @@ MHD_init_mem_pools_ (void)
  * Handle for a memory pool.  Pools are not reentrant and must not be
  * used by multiple threads.
  */
-struct MemoryPool
+struct mhd_MemoryPool
 {
 
   /**
@@ -274,15 +274,15 @@ struct MemoryPool
  * @param max maximum size of the pool
  * @return NULL on error
  */
-struct MemoryPool *
-MHD_pool_create (size_t max)
+MHD_INTERNAL struct mhd_MemoryPool *
+mdh_pool_create (size_t max)
 {
-  struct MemoryPool *pool;
+  struct mhd_MemoryPool *pool;
   size_t alloc_size;
 
   mhd_assert (max > 0);
   alloc_size = 0;
-  pool = malloc (sizeof (struct MemoryPool));
+  pool = malloc (sizeof (struct mhd_MemoryPool));
   if (NULL == pool)
     return NULL;
 #if defined(MAP_ANONYMOUS) || defined(_WIN32)
@@ -345,8 +345,8 @@ MHD_pool_create (size_t max)
  *
  * @param pool memory pool to destroy
  */
-void
-MHD_pool_destroy (struct MemoryPool *pool)
+MHD_INTERNAL void
+mhd_pool_destroy (struct mhd_MemoryPool *restrict pool)
 {
   if (NULL == pool)
     return;
@@ -378,8 +378,8 @@ MHD_pool_destroy (struct MemoryPool *pool)
  * @param pool pool to check
  * @return number of bytes still available in @a pool
  */
-size_t
-MHD_pool_get_free (struct MemoryPool *pool)
+MHD_INTERNAL size_t
+mhd_pool_get_free (struct mhd_MemoryPool *restrict pool)
 {
   mhd_assert (pool->end >= pool->pos);
   mhd_assert (pool->size >= pool->end - pool->pos);
@@ -403,8 +403,8 @@ MHD_pool_get_free (struct MemoryPool *pool)
  * @return NULL if the pool cannot support size more
  *         bytes
  */
-void *
-MHD_pool_allocate (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_allocate (struct mhd_MemoryPool *restrict pool,
                    size_t size,
                    bool from_end)
 {
@@ -444,9 +444,9 @@ MHD_pool_allocate (struct MemoryPool *pool,
  * @return true if block can be resized in-place in the optimal way,
  *         false otherwise
  */
-bool
-MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
-                               void *block,
+MHD_INTERNAL bool
+mhd_pool_is_resizable_inplace (struct mhd_MemoryPool *restrict pool,
+                               void *restrict block,
                                size_t block_size)
 {
   mhd_assert (pool->end >= pool->pos);
@@ -485,10 +485,10 @@ MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
  *         with amount of space needed to be freed in rellocatable area or
  *         set to SIZE_MAX if requested size is too large for the pool.
  */
-void *
-MHD_pool_try_alloc (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_try_alloc (struct mhd_MemoryPool *restrict pool,
                     size_t size,
-                    size_t *required_bytes)
+                    size_t *restrict required_bytes)
 {
   void *ret;
   size_t asize;
@@ -537,9 +537,9 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
  *         NULL if the pool cannot support @a new_size
  *         bytes (old continues to be valid for @a old_size)
  */
-void *
-MHD_pool_reallocate (struct MemoryPool *pool,
-                     void *old,
+MHD_INTERNAL void *
+mhd_pool_reallocate (struct mhd_MemoryPool *pool,
+                     void *restrict old,
                      size_t old_size,
                      size_t new_size)
 {
@@ -629,9 +629,9 @@ MHD_pool_reallocate (struct MemoryPool *pool,
  * @param block the allocated block, the NULL is tolerated
  * @param block_size the size of the allocated block
  */
-void
-MHD_pool_deallocate (struct MemoryPool *pool,
-                     void *block,
+MHD_INTERNAL void
+mhd_pool_deallocate (struct mhd_MemoryPool *restrict pool,
+                     void *restrict block,
                      size_t block_size)
 {
   mhd_assert (pool->end >= pool->pos);
@@ -733,9 +733,9 @@ MHD_pool_deallocate (struct MemoryPool *pool,
  *                 (should be larger or equal to @a copy_bytes)
  * @return addr new address of @a keep (if it had to change)
  */
-void *
-MHD_pool_reset (struct MemoryPool *pool,
-                void *keep,
+MHD_INTERNAL void *
+mhd_pool_reset (struct mhd_MemoryPool *restrict pool,
+                void *restrict keep,
                 size_t copy_bytes,
                 size_t new_size)
 {
diff --git a/src/mhd2/mhd_mempool.h b/src/mhd2/mhd_mempool.h
index 73ec1030..bc7dac46 100644
--- a/src/mhd2/mhd_mempool.h
+++ b/src/mhd2/mhd_mempool.h
@@ -25,8 +25,6 @@
  *        request
  * @author Christian Grothoff
  * @author Karlson2k (Evgeny Grin)
- *
- * TODO: Update code style
  */
 
 #ifndef MHD_MEMPOOL_H
@@ -41,13 +39,13 @@
  * Pools are not reentrant and must not be used
  * by multiple threads.
  */
-struct MemoryPool;
+struct mhd_MemoryPool;
 
 /**
  * Initialize values for memory pools
  */
 void
-MHD_init_mem_pools_ (void);
+mhd_init_mem_pools (void);
 
 
 /**
@@ -56,8 +54,8 @@ MHD_init_mem_pools_ (void);
  * @param max maximum size of the pool
  * @return NULL on error
  */
-struct MemoryPool *
-MHD_pool_create (size_t max);
+MHD_INTERNAL struct mhd_MemoryPool *
+mdh_pool_create (size_t max);
 
 
 /**
@@ -65,8 +63,8 @@ MHD_pool_create (size_t max);
  *
  * @param pool memory pool to destroy
  */
-void
-MHD_pool_destroy (struct MemoryPool *pool);
+MHD_INTERNAL void
+mhd_pool_destroy (struct mhd_MemoryPool *restrict pool);
 
 
 /**
@@ -80,8 +78,8 @@ MHD_pool_destroy (struct MemoryPool *pool);
  * @return NULL if the pool cannot support size more
  *         bytes
  */
-void *
-MHD_pool_allocate (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_allocate (struct mhd_MemoryPool *restrict pool,
                    size_t size,
                    bool from_end);
 
@@ -95,9 +93,9 @@ MHD_pool_allocate (struct MemoryPool *pool,
  * @return true if block can be resized in-place in the optimal way,
  *         false otherwise
  */
-bool
-MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
-                               void *block,
+MHD_INTERNAL bool
+mhd_pool_is_resizable_inplace (struct mhd_MemoryPool *restrict pool,
+                               void *restrict block,
                                size_t block_size);
 
 /**
@@ -119,10 +117,10 @@ MHD_pool_is_resizable_inplace (struct MemoryPool *pool,
  *         with amount of space needed to be freed in rellocatable area or
  *         set to SIZE_MAX if requested size is too large for the pool.
  */
-void *
-MHD_pool_try_alloc (struct MemoryPool *pool,
+MHD_INTERNAL void *
+mhd_pool_try_alloc (struct mhd_MemoryPool *restrict pool,
                     size_t size,
-                    size_t *required_bytes);
+                    size_t *restrict required_bytes);
 
 
 /**
@@ -142,9 +140,9 @@ MHD_pool_try_alloc (struct MemoryPool *pool,
  *         NULL if the pool cannot support @a new_size
  *         bytes (old continues to be valid for @a old_size)
  */
-void *
-MHD_pool_reallocate (struct MemoryPool *pool,
-                     void *old,
+MHD_INTERNAL void *
+mhd_pool_reallocate (struct mhd_MemoryPool *restrict pool,
+                     void *restrict old,
                      size_t old_size,
                      size_t new_size);
 
@@ -155,8 +153,8 @@ MHD_pool_reallocate (struct MemoryPool *pool,
  * @param pool pool to check
  * @return number of bytes still available in @a pool
  */
-size_t
-MHD_pool_get_free (struct MemoryPool *pool);
+MHD_INTERNAL size_t
+mhd_pool_get_free (struct mhd_MemoryPool *restrict pool);
 
 
 /**
@@ -171,9 +169,9 @@ MHD_pool_get_free (struct MemoryPool *pool);
  * @param block the allocated block, the NULL is tolerated
  * @param block_size the size of the allocated block
  */
-void
-MHD_pool_deallocate (struct MemoryPool *pool,
-                     void *block,
+MHD_INTERNAL void
+mhd_pool_deallocate (struct mhd_MemoryPool *restrict pool,
+                     void *restrict block,
                      size_t block_size);
 
 
@@ -190,9 +188,9 @@ MHD_pool_deallocate (struct MemoryPool *pool,
  *                 (should be larger or equal to @a copy_bytes)
  * @return addr new address of @a keep (if it had to change)
  */
-void *
-MHD_pool_reset (struct MemoryPool *pool,
-                void *keep,
+MHD_INTERNAL void *
+mhd_pool_reset (struct mhd_MemoryPool *restrict pool,
+                void *restrict keep,
                 size_t copy_bytes,
                 size_t new_size);
 
diff --git a/src/mhd2/mhd_recv.c b/src/mhd2/mhd_recv.c
index b909d510..979e4b53 100644
--- a/src/mhd2/mhd_recv.c
+++ b/src/mhd2/mhd_recv.c
@@ -42,7 +42,7 @@ static MHD_FN_PAR_NONNULL_ALL_
 MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
 mhd_plain_recv (struct MHD_Connection *restrict c,
                 size_t buf_size,
-                char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+                char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
                 size_t *restrict received)
 {
   /* Plain TCP connection */
@@ -59,25 +59,28 @@ mhd_plain_recv (struct MHD_Connection *restrict c,
     if (buf_size > (size_t) res)
       c->sk_ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
                     (((unsigned int) c->sk_ready)
-                     & (~mhd_SOCKET_NET_STATE_RECV_READY));
+                     & (~(enum mhd_SocketNetState)
+                        mhd_SOCKET_NET_STATE_RECV_READY));
     return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */
   }
 
-  err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+  err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
 
   if (mhd_SOCKET_ERR_AGAIN == err)
     c->sk_ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */
                   (((unsigned int) c->sk_ready)
-                   & (~mhd_SOCKET_NET_STATE_RECV_READY));
+                   & (~(enum mhd_SocketNetState)
+                      mhd_SOCKET_NET_STATE_RECV_READY));
 
   return err; /* Failure exit point */
 }
 
+
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
 MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
 mhd_recv (struct MHD_Connection *restrict c,
           size_t buf_size,
-          char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+          char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
           size_t *restrict received)
 {
   mhd_assert (MHD_INVALID_SOCKET != c->socket_fd);
@@ -85,5 +88,5 @@ mhd_recv (struct MHD_Connection *restrict c,
 
   // TODO: implement TLS support
 
-  return mhd_plain_recv(c, buf_size, buf, received);
+  return mhd_plain_recv (c, buf_size, buf, received);
 }
diff --git a/src/mhd2/mhd_reply.h b/src/mhd2/mhd_reply.h
index 3caf6384..e92a5530 100644
--- a/src/mhd2/mhd_reply.h
+++ b/src/mhd2/mhd_reply.h
@@ -99,12 +99,6 @@ struct MHD_Reply
    */
   struct MHD_Response *response;
 
-  /**
-   * HTTP response code.  Only valid if response object
-   * is already set.
-   */
-  unsigned int responseCode;
-
   /**
    * The "ICY" response.
    * Reply begins with the SHOUTcast "ICY" line instead of "HTTP".
diff --git a/src/mhd2/mhd_request.h b/src/mhd2/mhd_request.h
index a9e0f341..445e32b2 100644
--- a/src/mhd2/mhd_request.h
+++ b/src/mhd2/mhd_request.h
@@ -39,6 +39,7 @@
 #include "http_prot_ver.h"
 #include "http_method.h"
 #include "mhd_action.h"
+#include "mhd_buffer.h"
 
 
 /**
@@ -199,6 +200,36 @@ struct mhd_RequestField
 
 mhd_DLINKEDL_LIST_DEF (mhd_RequestField);
 
+
+/**
+ * The request content data
+ */
+struct mhd_ReqContentData
+{
+  /**
+   * The pointer to the large buffer
+   * Must be NULL if large buffer is not allocated.
+   */
+  struct mhd_Buffer lbuf;
+
+  /**
+   * The total size of the request content.
+   * #MHD_SIZE_UNKNOWN if the size is not yet known (chunked upload).
+   */
+  uint_fast64_t cntn_size;
+
+  /**
+   * The size of the received content
+   */
+  uint_fast64_t recv_size;
+
+  /**
+   * The size of the processed content
+   */
+  uint_fast64_t proc_size;
+};
+
+
 /**
  * Request-specific values.
  *
@@ -216,6 +247,11 @@ struct MHD_Request
    */
   struct mhd_ApplicationAction app_act;
 
+  /**
+   * The request content data
+   */
+  struct mhd_ReqContentData cntn;
+
   /**
    * HTTP version string (i.e. http/1.1).  Allocated
    * in pool.
@@ -271,12 +307,6 @@ struct MHD_Request
    */
   union MHD_StartOrSize field_lines;
 
-  /**
-   * How many more bytes of the body do we expect
-   * to read? #MHD_SIZE_UNKNOWN for unknown.
-   */
-  uint_fast64_t remaining_upload_size;
-
   /**
    * Are we receiving with chunked encoding?
    * This will be set to #MHD_YES after we parse the headers and
diff --git a/src/mhd2/mhd_response.h b/src/mhd2/mhd_response.h
index 0dd8c9b8..b89caf90 100644
--- a/src/mhd2/mhd_response.h
+++ b/src/mhd2/mhd_response.h
@@ -263,7 +263,7 @@ mhd_DLINKEDL_LIST_DEF (mhd_ResponseHeader);
 struct MHD_Response
 {
   /**
-   * The response status code
+   * The response HTTP status code
    */
   enum MHD_HTTP_StatusCode sc;
 
diff --git a/src/mhd2/mhd_send.c b/src/mhd2/mhd_send.c
index ce1c5591..5283960f 100644
--- a/src/mhd2/mhd_send.c
+++ b/src/mhd2/mhd_send.c
@@ -37,13 +37,16 @@
 
 #include "mhd_sys_options.h"
 
+#include <string.h>
+
 #include "mhd_send.h"
 #include "sys_sockets_headers.h"
 #include "sys_ip_headers.h"
 #include "mhd_sockets_macros.h"
 #include "daemon_logger.h"
 
-#include <string.h>
+#include "mhd_connection.h"
+#include "mhd_response.h"
 
 #include "mhd_iovec.h"
 #ifdef HAVE_LINUX_SENDFILE
@@ -74,8 +77,8 @@
 
 #ifdef mhd_USE_VECT_SEND
 #  if (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL)) && \
-    defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
-    defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED)
+  defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
+  defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED)
 #    define mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1
 #  endif /* (!HAVE_SENDMSG || !MSG_NOSIGNAL) &&
             mhd_SEND_SPIPE_SUPPRESS_POSSIBLE && mhd_SEND_SPIPE_SUPPRESS_NEEDED 
*/
@@ -124,13 +127,13 @@ freebsd_sendfile_init_ (void)
     freebsd_sendfile_flags_thd_p_c_ =
       SF_FLAGS ((uint_fast16_t) \
                 ((mhd_SENFILE_CHUNK_SIZE_FOR_THR_P_C + sys_page_size - 1) \
-                  / sys_page_size) & 0xFFFFU, SF_NODISKIO);
+                 / sys_page_size) & 0xFFFFU, SF_NODISKIO);
   }
 }
 
 
 #else  /* ! HAVE_FREEBSD_SENDFILE || ! SF_FLAGS */
-#  define freebsd_sendfile_init_() (void)0
+#  define freebsd_sendfile_init_() (void) 0
 #endif /* HAVE_FREEBSD_SENDFILE */
 
 
@@ -162,7 +165,7 @@ iov_max_init_ (void)
  */
 #  define mhd_IOV_MAX    mhd_iov_max_
 #else  /* ! HAVE_SYSCONF || ! _SC_IOV_MAX */
-#  define iov_max_init_() (void)0
+#  define iov_max_init_() (void) 0
 #    if defined(IOV_MAX)
 
 /**
@@ -197,7 +200,7 @@ mhd_connection_set_nodelay_state (struct MHD_Connection 
*connection,
   static const mhd_SCKT_OPT_BOOL on_val = 1;
   int err_code;
 
-  if (mhd_T_IS_YES(connection->is_nonip))
+  if (mhd_T_IS_YES (connection->is_nonip))
     return false;
 
   if (0 == setsockopt (connection->socket_fd,
@@ -211,10 +214,10 @@ mhd_connection_set_nodelay_state (struct MHD_Connection 
*connection,
   }
 
   err_code = mhd_SCKT_GET_LERR ();
-  if ((mhd_T_IS_NOT_YES(connection->is_nonip)) &&
-       (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
-        mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
-        mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
+  if ((mhd_T_IS_NOT_YES (connection->is_nonip)) &&
+      (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
+       mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
+       mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
   {
     connection->is_nonip = mhd_T_YES;
   }
@@ -240,7 +243,7 @@ mhd_connection_set_cork_state (struct MHD_Connection 
*connection,
   static const mhd_SCKT_OPT_BOOL on_val = 1;
   int err_code;
 
-  if (mhd_T_IS_YES(connection->is_nonip))
+  if (mhd_T_IS_YES (connection->is_nonip))
     return false;
 
   if (0 == setsockopt (connection->socket_fd,
@@ -254,10 +257,10 @@ mhd_connection_set_cork_state (struct MHD_Connection 
*connection,
   }
 
   err_code = mhd_SCKT_GET_LERR ();
-  if ((mhd_T_IS_NOT_YES(connection->is_nonip)) &&
-       (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
-        mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
-        mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
+  if ((mhd_T_IS_NOT_YES (connection->is_nonip)) &&
+      (mhd_SCKT_ERR_IS_EINVAL (err_code) ||
+       mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) ||
+       mhd_SCKT_ERR_IS_NOTSOCK (err_code)))
   {
     connection->is_nonip = mhd_T_YES;
   }
@@ -299,7 +302,7 @@ pre_send_setopt (struct MHD_Connection *connection,
    * Final piece is indicated by push_data == true. */
   const bool buffer_data = (! push_data);
 
-  if (mhd_T_IS_YES(connection->is_nonip))
+  if (mhd_T_IS_YES (connection->is_nonip))
     return;
 
   // TODO: support inheriting of TCP_NODELAY and TCP_NOPUSH
@@ -321,7 +324,7 @@ pre_send_setopt (struct MHD_Connection *connection,
 #endif /* ! mhd_USE_MSG_MORE */
 
 #ifdef mhd_TCP_CORK_NOPUSH
-    if (mhd_T_IS_YES(connection->sk_corked))
+    if (mhd_T_IS_YES (connection->sk_corked))
       return; /* The connection was already corked. */
 
     /* Prefer 'cork' over 'no delay' as the 'cork' buffers better, regardless
@@ -332,7 +335,7 @@ pre_send_setopt (struct MHD_Connection *connection,
     /* Failed to cork the connection.
      * Really unlikely to happen on TCP connections. */
 #endif /* mhd_TCP_CORK_NOPUSH */
-    if (mhd_T_IS_NO(connection->sk_nodelay))
+    if (mhd_T_IS_NO (connection->sk_nodelay))
       return; /* TCP_NODELAY was not set for the socket.
                * Nagle's algorithm will buffer some data. */
 
@@ -396,17 +399,17 @@ pre_send_setopt (struct MHD_Connection *connection,
   /* This is typical modern FreeBSD and OpenBSD behaviour. */
 #        endif /* ! mhd_NODELAY_SET_PUSH_DATA */
 
-  if (mhd_T_IS_YES(connection->sk_corked))
+  if (mhd_T_IS_YES (connection->sk_corked))
     return; /* Socket is corked. Data can be pushed by resetting of
              * TCP_CORK / TCP_NOPUSH after send() */
-  else if (mhd_T_IS_NO(connection->sk_corked))
+  else if (mhd_T_IS_NO (connection->sk_corked))
   {
     /* The socket is not corked. */
-    if (mhd_T_IS_YES(connection->sk_nodelay))
+    if (mhd_T_IS_YES (connection->sk_nodelay))
       return; /* TCP_NODELAY was already set,
                * data will be pushed automatically by the next send() */
 #        ifdef mhd_NODELAY_SET_PUSH_DATA
-    else if (mhd_T_IS_MAYBE(connection->sk_nodelay))
+    else if (mhd_T_IS_MAYBE (connection->sk_nodelay))
     {
       /* Setting TCP_NODELAY may push data NOW.
        * Cork socket here and uncork after send(). */
@@ -469,7 +472,7 @@ pre_send_setopt (struct MHD_Connection *connection,
              * TCP_CORK / TCP_NOPUSH after send() */
   /* The socket cannot be corked.
    * Really unlikely to happen on TCP connections */
-  if (mhd_T_IS_YES(connection->sk_nodelay))
+  if (mhd_T_IS_YES (connection->sk_nodelay))
     return; /* TCP_NODELAY was already set,
              * data will be pushed by the next send() */
 
@@ -498,11 +501,11 @@ pre_send_setopt (struct MHD_Connection *connection,
   /* This is old FreeBSD and Darwin behaviour. */
 
   /* Uncork socket if socket wasn't uncorked. */
-  if (mhd_T_IS_NOT_NO(connection->sk_corked))
+  if (mhd_T_IS_NOT_NO (connection->sk_corked))
     mhd_connection_set_cork_state (connection, false);
 
   /* Set TCP_NODELAY if it wasn't set. */
-  if (mhd_T_IS_NOT_YES(connection->sk_nodelay))
+  if (mhd_T_IS_NOT_YES (connection->sk_nodelay))
     mhd_connection_set_nodelay_state (connection, true);
 
   return;
@@ -524,7 +527,7 @@ pre_send_setopt (struct MHD_Connection *connection,
   /* Buffering of data is controlled only by
    * Nagel's algorithm. */
   /* Set TCP_NODELAY if it wasn't set. */
-  if (mhd_T_IS_NOT_YES(connection->sk_nodelay))
+  if (mhd_T_IS_NOT_YES (connection->sk_nodelay))
     mhd_connection_set_nodelay_state (connection, true);
 #endif /* ! mhd_TCP_CORK_NOPUSH */
 }
@@ -545,13 +548,12 @@ pre_send_setopt (struct MHD_Connection *connection,
 static bool
 zero_send (struct MHD_Connection *connection)
 {
-  static const int dummy;
+  static const int dummy = 0;
 
-  if (mhd_T_IS_YES(connection->is_nonip))
+  if (mhd_T_IS_YES (connection->is_nonip))
     return false;
-  mhd_assert (mhd_T_IS_NO(connection->sk_corked));
-  mhd_assert (mhd_T_IS_YES(connection->sk_nodelay));
-  dummy = 0; /* Mute compiler and analyzer warnings */
+  mhd_assert (mhd_T_IS_NO (connection->sk_corked));
+  mhd_assert (mhd_T_IS_YES (connection->sk_nodelay));
   if (0 == mhd_sys_send (connection->socket_fd, &dummy, 0))
     return true;
   MHD_LOG_MSG (connection->daemon, MHD_SC_SOCKET_ZERO_SEND_FAILED, \
@@ -581,7 +583,7 @@ post_send_setopt (struct MHD_Connection *connection,
    * Final piece is indicated by push_data == true. */
   const bool buffer_data = (! push_data);
 
-  if (mhd_T_IS_YES(connection->is_nonip))
+  if (mhd_T_IS_YES (connection->is_nonip))
     return;
   if (buffer_data)
     return; /* Nothing to do after the send(). */
@@ -592,8 +594,8 @@ post_send_setopt (struct MHD_Connection *connection,
 
   /* Need to push data. */
 #ifdef mhd_TCP_CORK_NOPUSH
-  if (mhd_T_IS_YES(connection->sk_nodelay) && \
-      mhd_T_IS_NO(connection->sk_corked))
+  if (mhd_T_IS_YES (connection->sk_nodelay) && \
+      mhd_T_IS_NO (connection->sk_corked))
     return; /* Data has been already pushed by last send(). */
 
 #  ifdef mhd_CORK_RESET_PUSH_DATA_ALWAYS
@@ -620,7 +622,7 @@ post_send_setopt (struct MHD_Connection *connection,
    * resetting of TCP_CORK so next final send without MSG_MORE will push
    * data to the network (without additional sys-call to push data).  */
 
-  if (mhd_T_IS_NOT_YES(connection->sk_nodelay) ||
+  if (mhd_T_IS_NOT_YES (connection->sk_nodelay) ||
       (! plain_send_next))
   {
     if (mhd_connection_set_nodelay_state (connection, true))
@@ -672,9 +674,9 @@ post_send_setopt (struct MHD_Connection *connection,
 #  else  /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */
   /* This is old FreeBSD or Darwin kernel. */
 
-  if (mhd_T_IS_NO(connection->sk_corked))
+  if (mhd_T_IS_NO (connection->sk_corked))
   {
-    mhd_assert(mhd_T_IS_NOT_YES(connection->sk_nodelay));
+    mhd_assert (mhd_T_IS_NOT_YES (connection->sk_nodelay));
 
     /* Unlikely to reach this code.
      * TCP_NODELAY should be turned on before send(). */
@@ -700,14 +702,14 @@ post_send_setopt (struct MHD_Connection *connection,
     {
 #ifdef mhd_CORK_RESET_PUSH_DATA
       /* Modern FreeBSD or OpenBSD kernel */
-      if (mhd_T_IS_YES(old_cork_state))
+      if (mhd_T_IS_YES (old_cork_state))
         return; /* Data has been pushed by uncorking the socket. */
 #endif /* mhd_CORK_RESET_PUSH_DATA */
 
       /* Unlikely to reach this code.
        * The data should be pushed by uncorking (FreeBSD) or
        * the socket should be uncorked before send(). */
-      if (mhd_T_IS_YES(connection->sk_nodelay) ||
+      if (mhd_T_IS_YES (connection->sk_nodelay) ||
           (mhd_connection_set_nodelay_state (connection, true)))
       {
         /* TCP_NODELAY is turned ON on uncorked socket.
@@ -722,8 +724,8 @@ post_send_setopt (struct MHD_Connection *connection,
 #else  /* ! mhd_TCP_CORK_NOPUSH */
   /* Corking is not supported. Buffering is controlled
    * by TCP_NODELAY only. */
-  mhd_assert (mhd_T_IS_NOT_YES(connection->sk_corked));
-  if (mhd_T_IS_YES(connection->sk_nodelay))
+  mhd_assert (mhd_T_IS_NOT_YES (connection->sk_corked));
+  if (mhd_T_IS_YES (connection->sk_nodelay))
     return; /* Data was already pushed by send(). */
 
   /* Unlikely to reach this code.
@@ -746,11 +748,13 @@ post_send_setopt (struct MHD_Connection *connection,
   return;
 }
 
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2)
+
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
 mhd_plain_send (struct MHD_Connection *restrict c,
                 size_t buf_size,
-                const char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+                const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
                 bool push_data,
                 size_t *restrict sent)
 {
@@ -766,12 +770,12 @@ mhd_plain_send (struct MHD_Connection *restrict c,
 
   pre_send_setopt (c, true, push_data);
 #ifdef mhd_USE_MSG_MORE
-  res = mhd_sys_send4 (s,
-                   buffer,
-                   buffer_size,
-                   push_data ? 0 : MSG_MORE);
+  res = mhd_sys_send4 (c->socket_fd,
+                       buffer,
+                       buffer_size,
+                       push_data ? 0 : MSG_MORE);
 #else
-  res = mhd_sys_send4 (c,
+  res = mhd_sys_send4 (c->socket_fd,
                        buf,
                        buf_size,
                        0);
@@ -781,12 +785,13 @@ mhd_plain_send (struct MHD_Connection *restrict c,
   {
     enum mhd_SocketError err;
 
-    err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+    err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
 
     if (mhd_SOCKET_ERR_AGAIN == err)
       c->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
                     (((unsigned int) c->sk_ready)
-                     & (~mhd_SOCKET_NET_STATE_SEND_READY));
+                     & (~(enum mhd_SocketNetState)
+                        mhd_SOCKET_NET_STATE_SEND_READY));
 
     return err;
   }
@@ -797,31 +802,32 @@ mhd_plain_send (struct MHD_Connection *restrict c,
   if (! full_buf_sent)
     c->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
                   (((unsigned int) c->sk_ready)
-                   & (~mhd_SOCKET_NET_STATE_SEND_READY));
+                   & (~(enum mhd_SocketNetState)
+                      mhd_SOCKET_NET_STATE_SEND_READY));
 
   /* If there is a need to push the data from network buffers
    * call post_send_setopt(). */
   /* It's unknown whether sendfile() (or other send function without
    * MSG_MORE support) will be used for the next reply so assume
    * that next sending will be the same, like this call. */
-  if ( push_data && full_buf_sent)
+  if (push_data && full_buf_sent)
     post_send_setopt (c, false, push_data);
 
   return mhd_SOCKET_ERR_NO_ERROR;
 }
 
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError
 mhd_send_data (struct MHD_Connection *restrict connection,
                size_t buf_size,
-               const char buf[MHD_FN_PAR_DYN_ARR_SIZE_(buf_size)],
+               const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
                bool push_data,
                size_t *restrict sent)
 {
   MHD_Socket s = connection->socket_fd;
 
-  enum mhd_SocketError ret;
   const bool tls_conn = false; // TODO: TLS support
 
   mhd_assert (MHD_INVALID_SOCKET != s);
@@ -838,10 +844,12 @@ mhd_send_data (struct MHD_Connection *restrict connection,
     return mhd_SOCKET_ERR_OTHER;
   }
 
-  return mhd_plain_send(connection, buf_size, buf, push_data, sent);
+  return mhd_plain_send (connection, buf_size, buf, push_data, sent);
 }
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_NONNULL_(3)
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3)
 MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_IN_SIZE_ (6,5) enum mhd_SocketError
 mhd_send_hdr_and_body (struct MHD_Connection *restrict connection,
                        size_t header_size,
@@ -920,17 +928,16 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict 
connection,
 #else  /* mhd_USE_VECT_SEND */
   no_vec = (no_vec || (0 == body_size));
   no_vec = (no_vec || ((sizeof(mhd_iov_elmn_size) <= sizeof(size_t)) &&
-      (((size_t) mhd_IOV_ELMN_MAX_SIZE) < header_size)));
+                       (((size_t) mhd_IOV_ELMN_MAX_SIZE) < header_size)));
 #endif /* mhd_USE_VECT_SEND */
 
 
-
   if (no_vec)
   {
     enum mhd_SocketError ret;
     ret = mhd_send_data (connection,
-                         header,
                          header_size,
+                         header,
                          push_hdr,
                          sent);
 
@@ -947,14 +954,14 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict 
connection,
        * the next round. */
 
       ret = mhd_send_data (connection,
-                           body,
                            body_size,
+                           body,
                            push_body,
                            &sent_b);
 
       if (mhd_SOCKET_ERR_NO_ERROR == ret)
         *sent += sent_b;
-      else if (mhd_SOCKET_ERR_IS_HARD(ret))
+      else if (mhd_SOCKET_ERR_IS_HARD (ret))
         return ret; /* Unrecoverable error */
 
       return mhd_SOCKET_ERR_NO_ERROR; /* The header has been sent successfully 
*/
@@ -971,8 +978,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict 
connection,
     push_body = complete_response;
   }
   if (((mhd_iov_ret_type) (header_size + body_size)) < 0 ||
-      ((size_t)(mhd_iov_ret_type) (header_size + body_size)) !=
-          (header_size + body_size))
+      ((size_t) (mhd_iov_ret_type) (header_size + body_size)) !=
+      (header_size + body_size))
   {
     /* Send sys-call total amount limit */
     body_size = mhd_IOV_RET_MAX_SIZE - header_size;
@@ -1004,8 +1011,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict 
connection,
   msg.msg_controllen = 0;
   msg.msg_flags = 0;
 
-  res = sendmsg (s, &msg, mhd_MSG_NOSIGNAL |
-                          ((push_hdr || push_body) ? 0 : mhd_MSG_MORE));
+  res = sendmsg (s, &msg, mhd_MSG_NOSIGNAL
+                 | ((push_hdr || push_body) ? 0 : mhd_MSG_MORE));
 #elif defined(HAVE_WRITEV)
   res = writev (s, vector, 2);
 #endif /* HAVE_WRITEV */
@@ -1038,19 +1045,21 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict 
connection,
   {
     enum mhd_SocketError err;
 
-    err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+    err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
 
     if (mhd_SOCKET_ERR_AGAIN == err)
       connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
                              (((unsigned int) connection->sk_ready)
-                              & (~mhd_SOCKET_NET_STATE_SEND_READY));
+                              & (~(enum mhd_SocketNetState)
+                                 mhd_SOCKET_NET_STATE_SEND_READY));
 
     return err;
   }
   if ((header_size + body_size) > *sent)
     connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
                            (((unsigned int) connection->sk_ready)
-                            & (~mhd_SOCKET_NET_STATE_SEND_READY));
+                            & (~(enum mhd_SocketNetState)
+                               mhd_SOCKET_NET_STATE_SEND_READY));
 
   /* If there is a need to push the data from network buffers
    * call post_send_setopt(). */
@@ -1091,7 +1100,8 @@ mhd_send_hdr_and_body (struct MHD_Connection *restrict 
connection,
 
 
 #if defined(MHD_USE_SENDFILE) // TODO: adapt, update
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (2) enum mhd_SocketError
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (2) enum mhd_SocketError
 mhd_send_sendfile (struct MHD_Connection *restrict connection,
                    size_t *restrict sent)
 {
@@ -1324,13 +1334,13 @@ mhd_send_sendfile (struct MHD_Connection *restrict 
connection,
  * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
  *         the sent size) or socket error
  */
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
 send_iov_nontls (struct MHD_Connection *restrict connection,
                  struct mhd_iovec_track *const restrict r_iov,
                  bool push_data,
                  size_t *restrict sent)
 {
-  ssize_t res;
   bool send_error;
   size_t items_to_send;
 #ifdef HAVE_SENDMSG
@@ -1410,12 +1420,13 @@ send_iov_nontls (struct MHD_Connection *restrict 
connection,
   {
     enum mhd_SocketError err;
 
-    err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR ());
+    err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
 
     if (mhd_SOCKET_ERR_AGAIN == err)
       connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
                              (((unsigned int) connection->sk_ready)
-                              & (~mhd_SOCKET_NET_STATE_SEND_READY));
+                              & (~(enum mhd_SocketNetState)
+                                 mhd_SOCKET_NET_STATE_SEND_READY));
 
     return err;
   }
@@ -1439,7 +1450,8 @@ send_iov_nontls (struct MHD_Connection *restrict 
connection,
     {
       connection->sk_ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */
                              (((unsigned int) connection->sk_ready)
-                              & (~mhd_SOCKET_NET_STATE_SEND_READY));
+                              & (~(enum mhd_SocketNetState)
+                                 mhd_SOCKET_NET_STATE_SEND_READY));
       if (0 != track_sent)
       {
         mhd_assert (r_iov->cnt > r_iov->sent);
@@ -1477,7 +1489,8 @@ send_iov_nontls (struct MHD_Connection *restrict 
connection,
  * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
  *         the sent size) or socket error
  */
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
 send_iov_emu (struct MHD_Connection *restrict connection,
               struct mhd_iovec_track *const restrict r_iov,
               bool push_data,
@@ -1485,33 +1498,31 @@ send_iov_emu (struct MHD_Connection *restrict 
connection,
 {
   const bool non_blk = connection->sk_nonblck;
   size_t total_sent;
-  size_t sent_elements;
   size_t max_elelements_to_sent;
 
   mhd_assert (NULL != r_iov->iov);
   total_sent = 0;
-  sent_elements = 0;
   max_elelements_to_sent = 8; /* Do not make too many sys-calls for just one 
connection */
   do
   {
     enum mhd_SocketError res;
     size_t sent_el_size;
 
-    if (total_sent > (size_t)(r_iov->iov[r_iov->sent].iov_len + total_sent))
+    if (total_sent > (size_t) (r_iov->iov[r_iov->sent].iov_len + total_sent))
       break; /* return value would overflow */
 
     res = mhd_send_data (connection,
-                          r_iov->iov[r_iov->sent].iov_base,
-                          r_iov->iov[r_iov->sent].iov_len,
-                          push_data && (r_iov->cnt == r_iov->sent + 1),
-                          &sent_el_size);
+                         r_iov->iov[r_iov->sent].iov_len,
+                         r_iov->iov[r_iov->sent].iov_base,
+                         push_data && (r_iov->cnt == r_iov->sent + 1),
+                         &sent_el_size);
     if (mhd_SOCKET_ERR_NO_ERROR == res)
     {
       /* Result is an error */
       if (0 == total_sent)
         return res; /* Nothing was sent, return error as is */
 
-      if (mhd_SOCKET_ERR_IS_HARD(res))
+      if (mhd_SOCKET_ERR_IS_HARD (res))
         return res; /* Any kind of a hard error */
 
       break; /* Return the amount of the sent data */
@@ -1543,7 +1554,8 @@ send_iov_emu (struct MHD_Connection *restrict connection,
 #endif /* !mhd_USE_VECT_SEND || HTTPS_SUPPORT
           || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
 mhd_send_iovec (struct MHD_Connection *restrict connection,
                 struct mhd_iovec_track *const restrict r_iov,
                 bool push_data,
@@ -1564,7 +1576,7 @@ mhd_send_iovec (struct MHD_Connection *restrict 
connection,
 #if defined(HTTPS_SUPPORT) || \
   defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
 #ifdef HTTPS_SUPPORT
-  use_iov_send = use_iov_send &
+  use_iov_send = use_iov_send &&
                  (true); // TODO: TLS support
 #endif /* HTTPS_SUPPORT */
 #ifdef mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED
@@ -1573,12 +1585,12 @@ mhd_send_iovec (struct MHD_Connection *restrict 
connection,
 #endif /* mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
   if (use_iov_send)
 #endif /* HTTPS_SUPPORT || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
-  return send_iov_nontls (connection, r_iov, push_data);
+  return send_iov_nontls (connection, r_iov, push_data, sent);
 #endif /* mhd_USE_VECT_SEND */
 
 #if ! defined(mhd_USE_VECT_SEND) || defined(HTTPS_SUPPORT) || \
   defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
-  return send_iov_emu (connection, r_iov, push_data);
+  return send_iov_emu (connection, r_iov, push_data, sent);
 #endif /* !mhd_USE_VECT_SEND || HTTPS_SUPPORT
           || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
 }
diff --git a/src/mhd2/mhd_socket_error.c b/src/mhd2/mhd_socket_error.c
index 449a9e1e..0c14e560 100644
--- a/src/mhd2/mhd_socket_error.c
+++ b/src/mhd2/mhd_socket_error.c
@@ -65,11 +65,12 @@ mhd_socket_error_get_from_socket (MHD_Socket fd)
 #if defined(SOL_SOCKET) && defined(SO_ERROR)
   enum mhd_SocketError err;
   int sock_err;
-  if (0 == setsockopt(fd, SOL_SOCKET, SOCKET_ERROR,
-                      (void *) &sock_err, sizeof(sock_err)))
+  sock_err = 0;
+  if (0 == setsockopt (fd, SOL_SOCKET, SOCKET_ERROR,
+                       (void *) &sock_err, sizeof(sock_err)))
     return mhd_socket_error_get_from_sys_err (sock_err);
 
-  err = mhd_socket_error_get_from_sys_err(mhd_SCKT_GET_LERR());
+  err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ());
   if ((mhd_SOCKET_ERR_NOTSOCK == err) ||
       (mhd_SOCKET_ERR_BADF == err))
     return err;
diff --git a/src/mhd2/mhd_str.h b/src/mhd2/mhd_str.h
index 0139233a..15678208 100644
--- a/src/mhd2/mhd_str.h
+++ b/src/mhd2/mhd_str.h
@@ -100,10 +100,10 @@ mhd_str_equal_caseless_bin_n (const char *const str1,
  * Comparison stops at first unmatched byte.
  * @param a the statically allocated string to compare
  * @param s the string to compare
- * @param len number of characters to compare
+ * @param l the number of characters in the @a s string
  * @return 'true' if two strings are equal, 'false' otherwise.
  */
-#define mhd_str_equal_caseless_s_bin_n(a,s,l) \
+#define mhd_str_equal_caseless_n_st(a,s,l) \
         ((mhd_SSTR_LEN (a) == (l)) \
          && mhd_str_equal_caseless_bin_n (a,s,l))
 
@@ -517,10 +517,10 @@ mhd_hex_to_bin (const char *restrict hex,
  *         small to hold the result
  */
 MHD_INTERNAL size_t
-mhd_str_pct_decode_strict_n_ (const char *pct_encoded,
-                              size_t pct_encoded_len,
-                              char *decoded,
-                              size_t buf_size);
+mhd_str_pct_decode_strict_n (const char *pct_encoded,
+                             size_t pct_encoded_len,
+                             char *decoded,
+                             size_t buf_size);
 
 /**
  * Decode string with percent-encoded characters as defined by
@@ -545,11 +545,11 @@ mhd_str_pct_decode_strict_n_ (const char *pct_encoded,
  *         zero if output buffer is too small to hold the result
  */
 MHD_INTERNAL size_t
-mhd_str_pct_decode_lenient_n_ (const char *pct_encoded,
-                               size_t pct_encoded_len,
-                               char *decoded,
-                               size_t buf_size,
-                               bool *broken_encoding);
+mhd_str_pct_decode_lenient_n (const char *pct_encoded,
+                              size_t pct_encoded_len,
+                              char *decoded,
+                              size_t buf_size,
+                              bool *broken_encoding);
 
 
 /**
@@ -589,7 +589,7 @@ mhd_str_pct_decode_in_place_strict (char *str);
  */
 MHD_INTERNAL size_t
 mhd_str_pct_decode_in_place_lenient (char *str,
-                                      bool *broken_encoding);
+                                     bool *broken_encoding);
 
 #ifdef DAUTH_SUPPORT
 /**
diff --git a/src/mhd2/request_funcs.c b/src/mhd2/request_funcs.c
index 6b3519f9..271a1add 100644
--- a/src/mhd2/request_funcs.c
+++ b/src/mhd2/request_funcs.c
@@ -41,20 +41,21 @@ mhd_stream_add_field_nullable (struct MHD_Connection 
*restrict c,
   struct mhd_RequestField *f;
 
   f = (struct mhd_RequestField *)
-       mhd_stream_alloc_memory (sizeof(struct mhd_RequestField));
+      mhd_stream_alloc_memory (c, sizeof(struct mhd_RequestField));
   if (NULL == f)
     return false;
 
-  f->field.nv.name = name;
-  f->field.nv.value = value;
+  f->field.nv.name = *name;
+  f->field.nv.value = *value;
   f->field.kind = kind;
-  mhd_DLINKEDL_INIT_LINKS(f, fields);
+  mhd_DLINKEDL_INIT_LINKS (f, fields);
 
-  mhd_DLINKEDL_INS_LAST(&(c->rq),f,fields);
+  mhd_DLINKEDL_INS_LAST (&(c->rq),f,fields);
 
   return true;
 }
 
+
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
 mhd_stream_add_field (struct MHD_Connection *restrict c,
                       enum MHD_ValueKind kind,
@@ -66,5 +67,5 @@ mhd_stream_add_field (struct MHD_Connection *restrict c,
   value2.len = value->len;
   value2.cstr = value->cstr;
 
-  return mhd_stream_add_field_nullable(c, kind, name, &value2);
+  return mhd_stream_add_field_nullable (c, kind, name, &value2);
 }
diff --git a/src/mhd2/request_get_value.c b/src/mhd2/request_get_value.c
index ca7a2b0b..7f3a5b32 100644
--- a/src/mhd2/request_get_value.c
+++ b/src/mhd2/request_get_value.c
@@ -34,35 +34,41 @@
 #include "mhd_public_api.h"
 
 #include "mhd_dlinked_list.h"
+#include "mhd_assert.h"
 
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) const struct MHD_String *
-mhd_request_get_value_len (struct MHD_Request *MHD_RESTRICT request,
-                           enum MHD_ValueKind kind,
-                           size_t key_len,
-                           const char *restrict key)
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_CSTR_ (4) const struct MHD_StringNullable *
+mhd_request_get_value_n (struct MHD_Request *MHD_RESTRICT request,
+                         enum MHD_ValueKind kind,
+                         size_t key_len,
+                         const char *restrict key)
 {
   struct mhd_RequestField *f;
 
-  for (f = mhd_DLINKEDL_GET_FIRST(request, fields); NULL != f;
-       f = mhd_DLINKEDL_GET_NEXT(f, fields))
+  mhd_assert (strlen (key) == key_len);
+
+  for (f = mhd_DLINKEDL_GET_FIRST (request, fields); NULL != f;
+       f = mhd_DLINKEDL_GET_NEXT (f, fields))
   {
     if ((key_len == f->field.nv.name.len) &&
         (kind == f->field.kind) &&
-        (0 == memcmp(key, f->field.nv.name.cstr)))
+        (0 == memcmp (key, f->field.nv.name.cstr, key_len)))
       return &(f->field.nv.value);
   }
   return NULL;
 }
 
-MHD_EXTERN_ MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) const struct MHD_String *
+
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) const struct MHD_StringNullable *
 MHD_request_get_value (struct MHD_Request *MHD_RESTRICT request,
                        enum MHD_ValueKind kind,
                        const char *MHD_RESTRICT key)
 {
   size_t len;
-  len = strlen(key);
-  return mhd_request_get_value_len(request, kind, len, key);
+  len = strlen (key);
+  return mhd_request_get_value_n (request, kind, len, key);
 }
diff --git a/src/mhd2/request_get_value.h b/src/mhd2/request_get_value.h
index 950bb523..a549972f 100644
--- a/src/mhd2/request_get_value.h
+++ b/src/mhd2/request_get_value.h
@@ -31,8 +31,10 @@
 #include "sys_base_types.h"
 #include "mhd_public_api.h"
 
+#include "mhd_str_macros.h"
+
 /**
- * Get a particular header (or other kind of request data) value.
+ * Get specified field value from request
  * If multiple values match the kind, return any one of them.
  *
  * The returned pointer is valid until the response is queued.
@@ -40,17 +42,35 @@
  *
  * @param request request to get values from
  * @param kind what kind of value are we looking for
+ * @param key_len the length of the @a key string
  * @param key the header to look for, empty to lookup 'trailing' value
  *            without a key
  * @return NULL if no such item was found
  * @ingroup request
  */
-MHD_INTERNAL const struct MHD_String *
-mhd_request_get_value_len (struct MHD_Request *restrict request,
-                           enum MHD_ValueKind kind,
-                           size_t key_len,
-                           const char *restrict key)
+MHD_INTERNAL const struct MHD_StringNullable *
+mhd_request_get_value_n (struct MHD_Request *restrict request,
+                         enum MHD_ValueKind kind,
+                         size_t key_len,
+                         const char *restrict key)
 MHD_FN_PAR_NONNULL_ (1)
 MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_CSTR_ (4);
 
+/**
+ * Get specified field value from request
+ * If multiple values match the kind, return any one of them.
+ *
+ * The returned pointer is valid until the response is queued.
+ * If the data is needed beyond this point, it should be copied.
+ *
+ * @param request request to get values from
+ * @param kind what kind of value are we looking for
+ * @param key the header to look for, empty to lookup 'trailing' value
+ *            without a key; must be a static string or array
+ * @return NULL if no such item was found
+ * @ingroup request
+ */
+#define mhd_request_get_value_st(r,k,str) \
+        mhd_request_get_value_n ((r),(k),mhd_SSTR_LEN (str),(str))
+
 #endif /* ! MHD_REQUEST_GET_VALUE_H */
diff --git a/src/mhd2/respond_with_error.h b/src/mhd2/respond_with_error.h
new file mode 100644
index 00000000..3dc8930b
--- /dev/null
+++ b/src/mhd2/respond_with_error.h
@@ -0,0 +1,86 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+
+*/
+
+/**
+ * @file src/mhd2/respond_with_error.h
+ * @brief  The declaration of error response functions and helper macros
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_RESPOND_WITH_ERROR_H
+#define MHD_RESPOND_WITH_ERROR_H 1
+
+#include "mhd_sys_options.h"
+#include "sys_base_types.h"
+#include "sys_null_macro.h"
+#include "mhd_str_macros.h"
+
+struct MHD_Connection; /* forward declaration */
+
+MHD_INTERNAL void
+respond_with_error_len (struct MHD_Connection *c,
+                        unsigned int http_code,
+                        size_t msg_len,
+                        const char *msg,
+                        size_t add_hdr_name_len,
+                        const char *add_hdr_name,
+                        size_t add_hdr_value_len,
+                        const char *add_hdr_value)
+MHD_FN_PAR_NONNULL_ (1)
+MHD_FN_PAR_CSTR_ (4) MHD_FN_PAR_CSTR_ (6) MHD_FN_PAR_CSTR_ (8);
+
+#ifdef HAVE_HTTP_AUTO_MESSAGES_BODIES
+/**
+ * Transmit static string as error response
+ */
+#  define mhd_RESPOND_WITH_ERROR_STATIC(c, code, msg) \
+        respond_with_error_len ((c), (code), \
+                                mhd_SSTR_LEN (msg), (msg), \
+                                0, NULL, 0, NULL)
+
+/**
+ * Transmit static string as error response and add specified header
+ */
+#  define mhd_RESPOND_WITH_ERROR_HEADER(c,code,m,hd_n_l,hd_n,hd_v_l,hd_v) \
+        respond_with_error_len ((c), (code), \
+                                mhd_SSTR_LEN (m), (m), \
+                                (hd_n_l), (hd_n), \
+                                (hd_v_l), (hd_v))
+
+#else
+/**
+ * Transmit static string as error response
+ */
+#  define mhd_RESPOND_WITH_ERROR_STATIC(c, code, msg) \
+        respond_with_error_len ((c), (code), \
+                                0, NULL, \
+                                0, NULL, 0, NULL)
+
+/**
+ * Transmit static string as error response and add specified header
+ */
+#  define mhd_RESPOND_WITH_ERROR_HEADER(c,code,m,hd_n_l,hd_n,hd_v_l,hd_v) \
+        respond_with_error_len ((c), (code), \
+                                0, NULL, \
+                                (hd_n_l), (hd_n), \
+                                (hd_v_l), (hd_v))
+#endif
+
+#endif /* ! MHD_RESPOND_WITH_ERROR_H */
diff --git a/src/mhd2/response_add_header.c b/src/mhd2/response_add_header.c
index e563239c..b8751ba3 100644
--- a/src/mhd2/response_add_header.c
+++ b/src/mhd2/response_add_header.c
@@ -26,6 +26,7 @@
 
 #include "mhd_sys_options.h"
 
+#include "response_add_header.h"
 #include "mhd_response.h"
 #include "mhd_locks.h"
 
@@ -34,26 +35,27 @@
 #include "mhd_public_api.h"
 
 
-MHD_INTERNAL
+static
 MHD_FN_PAR_NONNULL_ (1)
-MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) MHD_FN_PAR_IN_SIZE_(3,2)
-MHD_FN_PAR_NONNULL_ (5) MHD_FN_PAR_CSTR_ (5) MHD_FN_PAR_IN_SIZE_(5,4) bool
+MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3) MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_FN_PAR_NONNULL_ (5) MHD_FN_PAR_CSTR_ (5) MHD_FN_PAR_IN_SIZE_ (5,4) bool
 response_add_header_no_check (
   struct MHD_Response *response,
   size_t name_len,
-  const char name[MHD_FN_PAR_DYN_ARR_SIZE_(name_len)],
+  const char name[MHD_FN_PAR_DYN_ARR_SIZE_ (name_len)],
   size_t value_len,
-  const char value[MHD_FN_PAR_DYN_ARR_SIZE_(value_len)])
+  const char value[MHD_FN_PAR_DYN_ARR_SIZE_ (value_len)])
 {
   char *buf;
   struct mhd_ResponseHeader *new_hdr;
 
-  buf = malloc (sizeof(struct mhd_ResponseHeader) + name_len + value_len + 2);
-  if (NULL == buf)
+  new_hdr = (struct mhd_ResponseHeader *)
+            malloc (sizeof(struct mhd_ResponseHeader) + name_len
+                    + value_len + 2);
+  if (NULL == new_hdr)
     return false;
 
-  new_hdr = (struct mhd_ResponseHeader *) buf;
-  buf += sizeof(struct mhd_ResponseHeader);
+  buf = ((char *) new_hdr) + sizeof(struct mhd_ResponseHeader);
   memcpy (buf, name, name_len);
   buf[name_len] = 0;
   new_hdr->name.cstr = buf;
@@ -68,15 +70,17 @@ response_add_header_no_check (
   return true;
 }
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) void
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) void
 mhd_response_remove_all_headers (struct MHD_Response *restrict r)
 {
   struct mhd_ResponseHeader *hdr;
 
-  for (hdr = mhd_DLINKEDL_GET_LAST(r, headers); NULL != hdr;
-       hdr = mhd_DLINKEDL_GET_LAST(r, headers))
+  for (hdr = mhd_DLINKEDL_GET_LAST (r, headers); NULL != hdr;
+       hdr = mhd_DLINKEDL_GET_LAST (r, headers))
   {
-    mhd_DLINKEDL_DEL(r, hdr, headers);
+    mhd_DLINKEDL_DEL (r, hdr, headers);
     free (hdr);
   }
 }
@@ -103,7 +107,8 @@ response_add_header_int (struct MHD_Response *response,
       (NULL != memchr (value, '\r', value_len)))
     return MHD_SC_RESP_HEADER_VALUE_INVALID;
 
-  if (!response_add_header_no_check(response, name_len, name, value_len, 
value))
+  if (! response_add_header_no_check (response, name_len, name,
+                                      value_len, value))
     return MHD_SC_RESPONSE_HEADER_MALLOC_FAILED;
 
   return MHD_SC_OK;
@@ -129,7 +134,7 @@ MHD_response_add_header (struct MHD_Response *response,
     need_unlock = true;
     if (! mhd_mutex_lock (&(response->reuse.settings_lock)))
       return MHD_SC_RESPONSE_MUTEX_LOCK_FAILED;
-    mhd_assert (1 == mhd_atomic_counter_get(&(response->reuse.counter)));
+    mhd_assert (1 == mhd_atomic_counter_get (&(response->reuse.counter)));
   }
   else
     need_unlock = false;
diff --git a/src/mhd2/response_destroy.c b/src/mhd2/response_destroy.c
index 95bfaf02..defde693 100644
--- a/src/mhd2/response_destroy.c
+++ b/src/mhd2/response_destroy.c
@@ -35,6 +35,7 @@
 
 #include "response_add_header.h"
 #include "response_funcs.h"
+#include "response_from.h"
 
 /**
  * Perform full response de-initialisation, with cleaning-up / freeing
@@ -47,8 +48,8 @@ response_full_detinit (struct MHD_Response *restrict r)
 {
   mhd_response_remove_all_headers (r);
   if (r->reuse.reusable)
-    mhd_response_deinit_reusable(r);
-  mhd_response_deinit_content_data(r);
+    mhd_response_deinit_reusable (r);
+  mhd_response_deinit_content_data (r);
   free (r);
 }
 
@@ -56,11 +57,11 @@ response_full_detinit (struct MHD_Response *restrict r)
 MHD_INTERNAL void
 mhd_response_dec_use_count (struct MHD_Response *restrict r)
 {
-  mhd_assert(r->frozen);
+  mhd_assert (r->frozen);
 
   if (r->reuse.reusable)
   {
-    if (0 != mhd_atomic_counter_dec_get(&(r->reuse.counter)))
+    if (0 != mhd_atomic_counter_dec_get (&(r->reuse.counter)))
       return; /* The response is still used somewhere */
   }
 
@@ -68,7 +69,8 @@ mhd_response_dec_use_count (struct MHD_Response *restrict r)
 }
 
 
-MHD_EXTERN_ MHD_FN_PAR_NONNULL_ (1) void
+MHD_EXTERN_
+MHD_FN_PAR_NONNULL_ (1) void
 MHD_response_destroy (struct MHD_Response *response)
 {
   if (! response->frozen)
@@ -78,7 +80,7 @@ MHD_response_destroy (struct MHD_Response *response)
     free (response->settings);
 #ifndef NDEBUG
     /* Decrement counter to avoid triggering assert in deinit function */
-    mhd_assert (0 == mhd_atomic_counter_dec_get(&(response->reuse.counter)));
+    mhd_assert (0 == mhd_atomic_counter_dec_get (&(response->reuse.counter)));
 #endif
     response_full_detinit (response);
     return;
diff --git a/src/mhd2/response_funcs.c b/src/mhd2/response_funcs.c
index a4b27312..6853592f 100644
--- a/src/mhd2/response_funcs.c
+++ b/src/mhd2/response_funcs.c
@@ -32,39 +32,42 @@
 #include "mhd_response.h"
 #include "response_funcs.h"
 #include "mhd_locks.h"
+#include "response_options.h"
 
 
 #include "mhd_atomic_counter.h"
 
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) bool
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) bool
 response_make_reusable (struct MHD_Response *restrict r)
 {
   mhd_assert (! r->reuse.reusable);
   mhd_assert (! r->frozen);
   mhd_assert (NULL != r->settings);
 
-  if (mhd_mutex_init(&(r->reuse.settings_lock)))
+  if (mhd_mutex_init (&(r->reuse.settings_lock)))
   {
-    if (mhd_atomic_counter_init(&(r->reuse.counter), 1))
+    if (mhd_atomic_counter_init (&(r->reuse.counter), 1))
     {
       r->reuse.reusable = true;
       return true;
     }
-    (void) mhd_mutex_destroy(&(r->reuse.settings_lock));
+    (void) mhd_mutex_destroy (&(r->reuse.settings_lock));
   }
   return false;
 }
 
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ (1) void
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) void
 mhd_response_deinit_reusable (struct MHD_Response *restrict r)
 {
-  mhd_assert(r->reuse.reusable);
-  mhd_assert(0 == mhd_atomic_counter_get(&(r->reuse.counter)));
+  mhd_assert (r->reuse.reusable);
+  mhd_assert (0 == mhd_atomic_counter_get (&(r->reuse.counter)));
 
-  mhd_atomic_counter_deinit(&(r->reuse.counter));
-  mhd_mutex_destroy_chk(&(r->reuse.settings_lock));
+  mhd_atomic_counter_deinit (&(r->reuse.counter));
+  mhd_mutex_destroy_chk (&(r->reuse.settings_lock));
 }
 
 
@@ -110,7 +113,7 @@ mhd_response_check_frozen_freeze (struct MHD_Response 
*restrict response)
   {
     need_unlock = true;
     mhd_mutex_lock_chk (&(response->reuse.settings_lock));
-    mhd_assert (1 == mhd_atomic_counter_get(&(response->reuse.counter)));
+    mhd_assert (1 == mhd_atomic_counter_get (&(response->reuse.counter)));
   }
   else
     need_unlock = false;
diff --git a/src/mhd2/response_set_options.c b/src/mhd2/response_set_options.c
index cd56338f..ec4682ef 100644
--- a/src/mhd2/response_set_options.c
+++ b/src/mhd2/response_set_options.c
@@ -18,6 +18,7 @@
 #include "mhd_public_api.h"
 #include "mhd_locks.h"
 #include "mhd_assert.h"
+#include "response_funcs.h"
 
 /**
  * Internal version of the #MHD_response_set_options()
diff --git a/src/mhd2/stream_funcs.c b/src/mhd2/stream_funcs.c
index 51260411..580dbafc 100644
--- a/src/mhd2/stream_funcs.c
+++ b/src/mhd2/stream_funcs.c
@@ -39,17 +39,17 @@ MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void *
 mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
                          size_t size)
 {
-  struct MemoryPool *const restrict pool = c->pool;     /* a short alias */
+  struct mhd_MemoryPool *const restrict pool = c->pool;     /* a short alias */
   size_t need_to_be_freed = 0; /**< The required amount of additional free 
memory */
   void *res;
 
-  res = MHD_pool_try_alloc (pool,
+  res = mhd_pool_try_alloc (pool,
                             size,
                             &need_to_be_freed);
   if (NULL != res)
     return res;
 
-  if (MHD_pool_is_resizable_inplace (pool,
+  if (mhd_pool_is_resizable_inplace (pool,
                                      c->write_buffer,
                                      c->write_buffer_size))
   {
@@ -58,7 +58,7 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
     {
       char *buf;
       const size_t new_buf_size = c->write_buffer_size - need_to_be_freed;
-      buf = MHD_pool_reallocate (pool,
+      buf = mhd_pool_reallocate (pool,
                                  c->write_buffer,
                                  c->write_buffer_size,
                                  new_buf_size);
@@ -71,7 +71,7 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
     else
       return NULL;
   }
-  else if (MHD_pool_is_resizable_inplace (pool,
+  else if (mhd_pool_is_resizable_inplace (pool,
                                           c->read_buffer,
                                           c->read_buffer_size))
   {
@@ -79,7 +79,7 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
     {
       char *buf;
       const size_t new_buf_size = c->read_buffer_size - need_to_be_freed;
-      buf = MHD_pool_reallocate (pool,
+      buf = mhd_pool_reallocate (pool,
                                  c->read_buffer,
                                  c->read_buffer_size,
                                  new_buf_size);
@@ -93,12 +93,90 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
   }
   else
     return NULL;
-  res = MHD_pool_allocate (pool, size, true);
+  res = mhd_pool_allocate (pool, size, true);
   mhd_assert (NULL != res); /* It has been checked that pool has enough space 
*/
   return res;
 }
 
 
+/**
+ * Shrink stream read buffer to the zero size of free space in the buffer
+ * @param c the connection whose read buffer is being manipulated
+ */
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_shrink_read_buffer (struct MHD_Connection *restrict c)
+{
+  void *new_buf;
+
+  if ((NULL == c->read_buffer) || (0 == c->read_buffer_size))
+  {
+    mhd_assert (0 == c->read_buffer_size);
+    mhd_assert (0 == c->read_buffer_offset);
+    return;
+  }
+
+  mhd_assert (c->read_buffer_offset <= c->read_buffer_size);
+  if (0 == c->read_buffer_offset)
+  {
+    mhd_pool_deallocate (c->pool, c->read_buffer, c->read_buffer_size);
+    c->read_buffer = NULL;
+    c->read_buffer_size = 0;
+  }
+  else
+  {
+    mhd_assert (mhd_pool_is_resizable_inplace (c->pool, c->read_buffer, \
+                                               c->read_buffer_size));
+    new_buf = mhd_pool_reallocate (c->pool, c->read_buffer, 
c->read_buffer_size,
+                                   c->read_buffer_offset);
+    mhd_assert (c->read_buffer == new_buf);
+    c->read_buffer = new_buf;
+    c->read_buffer_size = c->read_buffer_offset;
+  }
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ size_t
+mhd_stream_maximize_write_buffer (struct MHD_Connection *restrict c)
+{
+  struct mhd_MemoryPool *const restrict pool = c->pool;
+  void *new_buf;
+  size_t new_size;
+  size_t free_size;
+
+  mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
+  mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset);
+  mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset);
+
+  free_size = mhd_pool_get_free (pool);
+  if (0 != free_size)
+  {
+    new_size = c->write_buffer_size + free_size;
+    /* This function must not move the buffer position.
+     * mhd_pool_reallocate () may return the new position only if buffer was
+     * allocated 'from_end' or is not the last allocation,
+     * which should not happen. */
+    mhd_assert ((NULL == c->write_buffer) || \
+                mhd_pool_is_resizable_inplace (pool, c->write_buffer, \
+                                               c->write_buffer_size));
+    new_buf = mhd_pool_reallocate (pool,
+                                   c->write_buffer,
+                                   c->write_buffer_size,
+                                   new_size);
+    mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer));
+    c->write_buffer = new_buf;
+    c->write_buffer_size = new_size;
+    if (c->write_buffer_send_offset == c->write_buffer_append_offset)
+    {
+      /* All data have been sent, reset offsets to zero. */
+      c->write_buffer_send_offset = 0;
+      c->write_buffer_append_offset = 0;
+    }
+  }
+
+  return c->write_buffer_size - c->write_buffer_append_offset;
+}
+
+
 #ifndef MHD_MAX_REASONABLE_HEADERS_SIZE_
 /**
  * A reasonable headers size (excluding request line) that should be sufficient
@@ -169,7 +247,8 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict c,
 #endif /* ! MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ */
 
 
-MHD_INTERNAL MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_IN_SIZE_(4,3) unsigned int
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_SIZE_ (4,3) unsigned int
 mhd_stream_get_no_space_err_status_code (struct MHD_Connection *restrict c,
                                          enum MHD_ProcRecvDataStage stage,
                                          size_t add_element_size,
@@ -220,8 +299,8 @@ mhd_stream_get_no_space_err_status_code (struct 
MHD_Connection *restrict c,
       && ( (0 == add_element[header_host_key_len])
            || (':' == add_element[header_host_key_len]) )
       && mhd_str_equal_caseless_bin_n (MHD_HTTP_HEADER_HOST,
-                                        add_element,
-                                        header_host_key_len);
+                                       add_element,
+                                       header_host_key_len);
     if (is_host_header)
     {
       const bool is_parsed = ! (
@@ -249,11 +328,11 @@ mhd_stream_get_no_space_err_status_code (struct 
MHD_Connection *restrict c,
   {
     static const size_t host_field_name_len =
       mhd_SSTR_LEN (MHD_HTTP_HEADER_HOST);
-    struct MHD_String *host_value;
-    host_value = mhd_request_get_value_len(&(c->rq),
-                                           MHD_VK_HEADER,
-                                           MHD_HTTP_HEADER_HOST,
-                                           host_field_name_len);
+    const struct MHD_StringNullable *host_value;
+    host_value = mhd_request_get_value_n (&(c->rq),
+                                          MHD_VK_HEADER,
+                                          host_field_name_len,
+                                          MHD_HTTP_HEADER_HOST);
     if (NULL != host_value)
     {
       /* Calculate the minimal size of the field line: no space between
@@ -369,3 +448,11 @@ mhd_stream_get_no_space_err_status_code (struct 
MHD_Connection *restrict c,
 
   return MHD_HTTP_STATUS_URI_TOO_LONG;
 }
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_switch_from_recv_to_send (struct MHD_Connection *c)
+{
+  /* Read buffer is not needed for this request, shrink it.*/
+  mhd_stream_shrink_read_buffer (c);
+}
diff --git a/src/mhd2/stream_funcs.h b/src/mhd2/stream_funcs.h
index 0e775dbe..697fde5e 100644
--- a/src/mhd2/stream_funcs.h
+++ b/src/mhd2/stream_funcs.h
@@ -30,6 +30,7 @@
 #include "mhd_sys_options.h"
 #include "sys_base_types.h"
 
+
 struct MHD_Connection; /* forward declaration */
 
 
@@ -64,6 +65,25 @@ mhd_stream_alloc_memory (struct MHD_Connection *restrict 
connection,
                          size_t size)
 MHD_FN_PAR_NONNULL_ALL_;
 
+/**
+ * Shrink stream read buffer to the zero size of free space in the buffer
+ * @param c the connection whose read buffer is being manipulated
+ */
+MHD_INTERNAL void
+mhd_stream_shrink_read_buffer (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Allocate the maximum available amount of memory from MemoryPool
+ * for write buffer.
+ * @param c the connection whose write buffer is being manipulated
+ * @return the size of the free space in the write buffer
+ */
+MHD_INTERNAL size_t
+mhd_stream_maximize_write_buffer (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
 /**
  * Select the HTTP error status code for "out of receive buffer space" error.
  * @param c the connection to process
@@ -81,6 +101,69 @@ mhd_stream_get_no_space_err_status_code (struct 
MHD_Connection *restrict c,
                                          enum MHD_ProcRecvDataStage stage,
                                          size_t add_element_size,
                                          const char *restrict add_element)
-MHD_FN_PAR_NONNULL_(1) MHD_FN_PAR_IN_SIZE_(4,3);
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_SIZE_ (4,3);
+
+/**
+ * Switch connection from recv mode to send mode.
+ *
+ * Current request header or body will not be read anymore,
+ * response must be assigned to connection.
+ * @param c the connection to prepare for sending.
+ */
+MHD_INTERNAL void
+mhd_stream_switch_from_recv_to_send (struct MHD_Connection *c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+enum mhd_StreamAbortReason
+{
+  mhd_STREAM_ABORT_CLIENT_HTTP_ERR
+};
+
+/**
+ * Close stream with error
+ *
+ * @param c the connection to close.
+ */
+MHD_INTERNAL void
+mhd_stream_abort (struct MHD_Connection *c,
+                  enum mhd_StreamAbortReason reason,
+                  const char *log_msg)
+MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3);
+
+#ifdef HAVE_LOG_FUNCTIONALITY
+#  define mhd_STREAM_ABORT(c,r,m) (mhd_stream_abort ((c),(r),(m)))
+#else  /* ! HAVE_LOG_FUNCTIONALITY */
+#  define mhd_STREAM_ABORT(c,r,m) (mhd_stream_abort ((c),(r),NULL))
+#endif /* ! HAVE_LOG_FUNCTIONALITY */
+
+/**
+ * Update last activity mark to the current time..
+ * @param c the connection to update
+ */
+MHD_INTERNAL void
+mhd_stream_update_activity_mark (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Perform initial clean-up and mark for closing.
+ * Set the reason to "aborted by application"
+ * @param c to make
+ */
+MHD_INTERNAL void
+mhd_conn_pre_close_app_abort (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/**
+ * Perform initial clean-up and mark for closing.
+ * Set the reason to "socket error"
+ * @param c to make
+ */
+MHD_INTERNAL void
+mhd_conn_pre_close_skt_err (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
 
 #endif /* ! MHD_STREAM_FUNCS_H */
diff --git a/src/mhd2/http_status_str.h b/src/mhd2/stream_process_reply.h
similarity index 62%
copy from src/mhd2/http_status_str.h
copy to src/mhd2/stream_process_reply.h
index 4906943b..2531fce6 100644
--- a/src/mhd2/http_status_str.h
+++ b/src/mhd2/stream_process_reply.h
@@ -19,28 +19,20 @@
 */
 
 /**
- * @file src/mhd2/http_status_str.h
- * @brief  The declaration for internal HTTP status string functions
+ * @file src/mhd2/stream_process_reply.h
+ * @brief  The declarations of internal functions for forming and sending
+ *         replies for requests
  * @author Karlson2k (Evgeny Grin)
  */
 
-#ifndef MHD_HTTP_STATUS_STR_H
-#define MHD_HTTP_STATUS_STR_H 1
+#ifndef MHD_STREAM_PROCESS_REPLY_H
+#define MHD_STREAM_PROCESS_REPLY_H 1
 
 #include "mhd_sys_options.h"
 
-#include "mhd_str_types.h"
+#include "sys_bool_type.h"
 
-/**
- * Get string for provided HTTP status code.
- * Substitute a replacement string for unknown codes.
- *
- * @param code the HTTP status code
- * @return pointer to MHD_String, never NULL.
- */
-MHD_INTERNAL const struct MHD_String *
-mhd_HTTP_status_code_to_string_int (enum MHD_HTTP_StatusCode code)
-MHD_FN_CONST_;
+struct MHD_Connection; /* forward declaration */
 
 
-#endif /* ! MHD_HTTP_STATUS_STR_H */
+#endif /* ! MHD_STREAM_PROCESS_REPLY_H */
diff --git a/src/mhd2/stream_process_request.c 
b/src/mhd2/stream_process_request.c
index 5250559a..19bf5e11 100644
--- a/src/mhd2/stream_process_request.c
+++ b/src/mhd2/stream_process_request.c
@@ -1,6 +1,7 @@
 /*
   This file is part of GNU libmicrohttpd
-  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+  Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
+  Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
 
   GNU libmicrohttpd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -23,23 +24,36 @@
  * @brief  The implementation of internal functions for requests parsing
  *         and processing
  * @author Karlson2k (Evgeny Grin)
+ *
+ * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
+ * contributors.
  */
 
 #include "mhd_sys_options.h"
+#include "stream_process_request.h"
 
 #include "sys_bool_type.h"
 #include "sys_base_types.h"
 
+#include "mhd_str_types.h"
 #include "mhd_str_macros.h"
+#include "mhd_str.h"
 
 #include <string.h>
 
+#include "mhd_daemon.h"
 #include "mhd_connection.h"
+#include "mhd_public_api.h"
 
-#include "mhd_str_types.h"
 #include "daemon_logger.h"
+#include "mhd_assert.h"
+#include "mhd_panic.h"
 
 #include "request_funcs.h"
+#include "request_get_value.h"
+#include "respond_with_error.h"
+#include "stream_funcs.h"
+#include "daemon_funcs.h"
 
 /**
  * Response text used when the request (http header) is
@@ -254,6 +268,95 @@
         "request target or a shorter request method token.</p></body>" \
         "</html>"
 
+/**
+ * Response text used when the request header is too big to be processed.
+ */
+#define ERR_RSP_REQUEST_FOOTER_TOO_BIG \
+        "<html>" \
+        "<head><title>Request too big</title></head>" \
+        "<body><p>The total size of the request headers, which includes the " \
+        "request target, the request field lines and the chunked trailer " \
+        "section exceeds the memory constraints of this web server.</p>" \
+        "<p>The request could be re-tried with a shorter chunked trailer " \
+        "section, shorter field lines, a shorter request target or " \
+        "a shorter request method token.</p></body>" \
+        "</html>"
+
+/**
+ * Response text used when the request (http header) is too big to
+ * be processed.
+ */
+#define ERR_RSP_MSG_REQUEST_TOO_BIG \
+        "<html>" \
+        "<head><title>Request too big</title></head>" \
+        "<body>Request HTTP header is too big for the memory constraints " \
+        "of this webserver.</body>" \
+        "</html>"
+
+/**
+ * Response text used when the request (http header) does not
+ * contain a "Host:" header and still claims to be HTTP 1.1.
+ */
+#define ERR_RSP_REQUEST_LACKS_HOST \
+        "<html>" \
+        "<head><title>&quot;Host:&quot; header required</title></head>" \
+        "<body>HTTP/1.1 request without <b>&quot;Host:&quot;</b>.</body>" \
+        "</html>"
+
+/**
+ * Response text used when the request has unsupported "Transfer-Encoding:".
+ */
+#define ERR_RSP_UNSUPPORTED_TR_ENCODING \
+        "<html>" \
+        "<head><title>Unsupported Transfer-Encoding</title></head>" \
+        "<body>The Transfer-Encoding used in request is not supported.</body>" 
\
+        "</html>"
+
+/**
+ * Response text used when the request has unsupported both headers:
+ * "Transfer-Encoding:" and "Content-Length:"
+ */
+#define ERR_RSP_REQUEST_CNTNLENGTH_WITH_TR_ENCODING \
+        "<html>" \
+        "<head><title>Malformed request</title></head>" \
+        "<body>Wrong combination of the request headers: both 
Transfer-Encoding " \
+        "and Content-Length headers are used at the same time.</body>" \
+        "</html>"
+
+/**
+ * Response text used when the request HTTP content is too large.
+ */
+#define ERR_RSP_REQUEST_CONTENTLENGTH_TOOLARGE \
+        "<html><head><title>Request content too large</title></head>" \
+        "<body>HTTP request has too large value for " \
+        "<b>Content-Length</b> header.</body></html>"
+
+/**
+ * Response text used when the request HTTP chunked encoding is
+ * malformed.
+ */
+#define ERR_RSP_REQUEST_CONTENTLENGTH_MALFORMED \
+        "<html><head><title>Request malformed</title></head>" \
+        "<body>HTTP request has wrong value for " \
+        "<b>Content-Length</b> header.</body></html>"
+
+
+/**
+ * Response text used when the request HTTP chunked encoding is
+ * malformed.
+ */
+#define ERR_RSP_REQUEST_CHUNKED_MALFORMED \
+        "<html><head><title>Request malformed</title></head>" \
+        "<body>HTTP chunked encoding is syntactically incorrect.</body></html>"
+
+/**
+ * Response text used when the request HTTP chunk is too large.
+ */
+#define ERR_RSP_REQUEST_CHUNK_TOO_LARGE \
+        "<html><head><title>Request content too large</title></head>" \
+        "<body>The chunk size used in HTTP chunked encoded " \
+        "request is too large.</body></html>"
+
 /**
  * Get whether bare LF in HTTP header and other protocol elements
  * should be treated as the line termination depending on the configured
@@ -265,7 +368,57 @@
 /**
  * The valid length of any HTTP version string
  */
-#define HTTP_VER_LEN (mhd_SSTR_LEN(MHD_HTTP_VERSION_1_1_STR))
+#define HTTP_VER_LEN (mhd_SSTR_LEN (MHD_HTTP_VERSION_1_1_STR))
+
+
+/**
+ * Detect standard HTTP request method
+ *
+ * @param connection the connection
+ * @param method the pointer to HTTP request method string
+ * @param len the length of @a method in bytes
+ */
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2) void
+parse_http_std_method (struct MHD_Connection *restrict connection,
+                       size_t len,
+                       const char *restrict method)
+{
+  const char *const m = method; /**< short alias */
+  mhd_assert (NULL != m);
+  mhd_assert (0 != len);
+
+  if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_GET) == len) &&
+      (0 == memcmp (m, MHD_HTTP_METHOD_STR_GET, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_GET;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_HEAD) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_HEAD, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_HEAD;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_POST) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_POST, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_POST;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_PUT) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_PUT, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_PUT;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_DELETE) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_DELETE, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_DELETE;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_CONNECT) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_CONNECT, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_CONNECT;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_OPTIONS) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_OPTIONS, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_OPTIONS;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_TRACE) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_TRACE, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_TRACE;
+  else if ((mhd_SSTR_LEN (MHD_HTTP_METHOD_STR_ASTERISK) == len) &&
+           (0 == memcmp (m, MHD_HTTP_METHOD_STR_ASTERISK, len)))
+    connection->rq.http_mthd = mhd_HTTP_METHOD_ASTERISK;
+  else
+    connection->rq.http_mthd = mhd_HTTP_METHOD_OTHER;
+}
+
 
 /**
  * Detect HTTP version, send error response if version is not supported
@@ -292,9 +445,9 @@ parse_http_version (struct MHD_Connection *restrict 
connection,
       || ('.' != h[6]))
   {
     connection->rq.http_ver = MHD_HTTP_VERSION_INVALID;
-    transmit_error_response_static (connection,
-                                    MHD_HTTP_STATUS_BAD_REQUEST,
-                                    ERR_RSP_REQUEST_MALFORMED);
+    mhd_RESPOND_WITH_ERROR_STATIC (connection,
+                                   MHD_HTTP_STATUS_BAD_REQUEST,
+                                   ERR_RSP_REQUEST_MALFORMED);
     return false;
   }
   if (1 == h[5] - '0')
@@ -318,20 +471,19 @@ parse_http_version (struct MHD_Connection *restrict 
connection,
   {
     /* Too old major version */
     connection->rq.http_ver = MHD_HTTP_VERSION_INVALID;
-    transmit_error_response_static (connection,
-                                    MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
-                                    ERR_RSP_REQ_HTTP_VER_IS_TOO_OLD);
+    mhd_RESPOND_WITH_ERROR_STATIC (connection,
+                                   MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
+                                   ERR_RSP_REQ_HTTP_VER_IS_TOO_OLD);
     return false;
   }
-  else if ((2 == h[5] - '0') &&
-      (('0' > h[7]) || ('9' < h[7])))
+  else if ((2 == h[5] - '0') && ('0' == h[7] - '0'))
     connection->rq.http_ver = MHD_HTTP_VERSION_2;
   else
     connection->rq.http_ver = MHD_HTTP_VERSION_INVALID;
 
-  transmit_error_response_static (connection,
-                                  MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
-                                  ERR_RSP_REQ_HTTP_VER_IS_NOT_SUPPORTED);
+  mhd_RESPOND_WITH_ERROR_STATIC (connection,
+                                 MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,
+                                 ERR_RSP_REQ_HTTP_VER_IS_NOT_SUPPORTED);
   return false;
 }
 
@@ -341,7 +493,7 @@ parse_http_version (struct MHD_Connection *restrict 
connection,
  * The maximum number of ignored empty line before the request line
  * at default "strictness" level.
  */
-#define MHD_MAX_EMPTY_LINES_SKIP 1024
+#  define MHD_MAX_EMPTY_LINES_SKIP 1024
 #endif /* ! MHD_MAX_EMPTY_LINES_SKIP */
 
 
@@ -353,7 +505,7 @@ parse_http_version (struct MHD_Connection *restrict 
connection,
  *         false if not enough data yet in the receive buffer
  */
 static MHD_FN_PAR_NONNULL_ALL_ bool
-mhd_get_request_line_inner (struct MHD_Connection *restrict c)
+get_request_line_inner (struct MHD_Connection *restrict c)
 {
   size_t p; /**< The current processing position */
   const int discp_lvl = c->daemon->req_cfg.strictnees;
@@ -457,9 +609,9 @@ mhd_get_request_line_inner (struct MHD_Connection *restrict 
c)
                               MHD_MAX_EMPTY_LINES_SKIP : 1)) <
              c->rq.hdrs.rq_line.skipped_empty_lines))
         {
-          connection_close_error (c,
-                                  _ ("Too many meaningless extra empty lines " 
\
-                                     "received before the request"));
+          mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                            "Too many meaningless extra empty lines " \
+                            "received before the request.");
           return true; /* Process connection closure */
         }
         if (0 == c->read_buffer_offset)
@@ -528,14 +680,15 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
           if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
               (mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
           {
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_BARE_CR_IN_HEADER);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_BARE_CR_IN_HEADER);
           }
           else
-            connection_close_error (c,
-                                    _ ("Bare CR characters are not allowed " \
-                                       "in the request line.\n"));
+            mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                              "Bare CR characters are not allowed " \
+                              "in the request line.");
+
           return true; /* Error in the request */
         }
       }
@@ -555,14 +708,14 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
         if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
             (mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
         {
-          transmit_error_response_static (c,
-                                          MHD_HTTP_STATUS_BAD_REQUEST,
-                                          ERR_RSP_BARE_LF_IN_HEADER);
+          mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                         MHD_HTTP_STATUS_BAD_REQUEST,
+                                         ERR_RSP_BARE_LF_IN_HEADER);
         }
         else
-          connection_close_error (c,
-                                  _ ("Bare LF characters are not allowed " \
-                                     "in the request line.\n"));
+          mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                            "Bare LF characters are not allowed " \
+                            "in the request line.");
         return true; /* Error in the request */
       }
     }
@@ -620,8 +773,8 @@ mhd_get_request_line_inner (struct MHD_Connection *restrict 
c)
               && (HTTP_VER_LEN == p - (size_t) (c->rq.hdrs.rq_line.rq_tgt
                                                 - read_buffer))
               && (0 != read_buffer[(size_t)
-                                      (c->rq.hdrs.rq_line.rq_tgt
-                                       - read_buffer) - 1]))
+                                   (c->rq.hdrs.rq_line.rq_tgt
+                                    - read_buffer) - 1]))
           {
             /* Found only HTTP method and HTTP version and more than one
                whitespace between them. Assume zero-length URI. */
@@ -680,13 +833,13 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
       if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
           (mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
       {
-        transmit_error_response_static (c,
-                                        MHD_HTTP_STATUS_BAD_REQUEST,
-                                        ERR_RSP_REQUEST_MALFORMED);
+        mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                       MHD_HTTP_STATUS_BAD_REQUEST,
+                                       ERR_RSP_REQUEST_MALFORMED);
       }
       else
-        connection_close_error (c,
-                                _ ("The request line is malformed.\n"));
+        mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                          "The request line is malformed.");
 
       return true;
     }
@@ -748,14 +901,13 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
           mhd_assert (NULL == c->rq.version);
           if (0 == p)
           {
-            connection_close_error (c,
-                                    _ ("The request line starts with "
-                                       "a whitespace.\n"));
+            mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                              "The request line starts with a whitespace.");
             return true; /* Error in the request */
           }
           read_buffer[p] = 0; /* Zero-terminate the request method string */
           c->rq.method = read_buffer;
-          parse_http_std_method (c, c->rq.method, p);
+          parse_http_std_method (c, p, c->rq.method);
         }
         else
         {
@@ -781,14 +933,14 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
               if ((mhd_HTTP_METHOD_GET <= c->rq.http_mthd) &&
                   (mhd_HTTP_METHOD_DELETE >= c->rq.http_mthd))
               {
-                transmit_error_response_static (c,
-                                                MHD_HTTP_STATUS_BAD_REQUEST,
-                                                ERR_RSP_RQ_LINE_TOO_MANY_WSP);
+                mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                               MHD_HTTP_STATUS_BAD_REQUEST,
+                                               ERR_RSP_RQ_LINE_TOO_MANY_WSP);
               }
               else
-                connection_close_error (c,
-                                        _ ("The request line has more than "
-                                           "two whitespaces.\n"));
+                mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                                  "The request line has more than "
+                                  "two whitespaces.");
               return true; /* Error in the request */
             }
           }
@@ -875,18 +1027,16 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
         }
         else
         {
-          connection_close_error (c,
-                                  _ ("Invalid character is in the "
-                                     "request line.\n"));
+          mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                            "Invalid character is in the request line.");
           return true; /* Error in the request */
         }
       }
       else if (0 == chr)
       {
         /* NUL character */
-        connection_close_error (c,
-                                _ ("The NUL character is in the "
-                                   "request line.\n"));
+        mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                          "The NUL character is in the request line.");
         return true; /* Error in the request */
       }
     }
@@ -898,8 +1048,294 @@ mhd_get_request_line_inner (struct MHD_Connection 
*restrict c)
   return false; /* Not enough data yet */
 }
 
+
+/**
+ * Callback for iterating over GET parameters
+ * @param cls the iterator metadata
+ * @param name the name of the parameter
+ * @param value the value of the parameter
+ * @return bool to continue iterations,
+ *         false to stop the iteration
+ */
+static MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) bool
+request_add_get_arg (void *restrict cls,
+                     const struct MHD_String *restrict name,
+                     const struct MHD_StringNullable *restrict value)
+{
+  struct MHD_Connection *c = (struct MHD_Connection *) cls;
+
+  return mhd_stream_add_field_nullable (c, MHD_VK_GET_ARGUMENT, name, value);
+}
+
+
+MHD_INTERNAL
+MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2)
+MHD_FN_PAR_INOUT_ (2) bool
+// TODO: detect and report errors
+mhd_parse_get_args (size_t args_len,
+                    char *restrict args,
+                    mhd_GetArgumentInter cb,
+                    void *restrict cls)
+{
+  size_t i;
+
+  mhd_assert (args_len < (size_t) (args_len + 1)); /* Does not work when 
args_len == SIZE_MAX */
+
+  for (i = 0; i < args_len; ++i) /* Looking for names of the parameters */
+  {
+    size_t name_start;
+    size_t name_len;
+    size_t value_start;
+    size_t value_len;
+    struct MHD_String name;
+    struct MHD_StringNullable value;
+
+    /* Found start of the name */
+
+    value_start = 0;
+    for (name_start = i; i < args_len; ++i) /* Processing parameter */
+    {
+      if ('+' == args[i])
+        args[i] = ' ';
+      else if ('=' == args[i])
+      {
+        /* Found start of the value */
+        args[i] = 0; /* zero-terminate the name */
+        for (value_start = ++i; i < args_len; ++i) /* Processing parameter 
value */
+        {
+          if ('+' == args[i])
+            args[i] = ' ';
+          else if ('&' == args[i]) /* delimiter for the next parameter */
+            break;
+        }
+        if (i < args_len)
+          args[i] = 0;
+        mhd_assert (0 == args[i]);
+        break; /* End if the parameter */
+      }
+    }
+
+    /* Store found parameter */
+
+    if (0 != value_start) /* Value cannot start at zero position */
+    { /* Name with value */
+      mhd_assert (name_start + 2 <= value_start);
+      name_len = value_start - name_start - 2;
+
+      value_len = mhd_str_pct_decode_lenient_n (args + value_start, value_len,
+                                                args + value_start, value_len,
+                                                NULL); // TODO: add support 
for broken encoding detection
+      value.cstr = args + value_start;
+      value.len = value_len;
+    }
+    else
+    { /* Name without value */
+      name_len = i - name_start;
+
+      value.cstr = NULL;
+      value.len = 0;
+    }
+    name_len = mhd_str_pct_decode_lenient_n (args + name_start, name_len,
+                                             args + name_start, name_len,
+                                             NULL); // TODO: add support for 
broken encoding detection
+    name.cstr = args + name_start;
+    name.len = name_len;
+    if (! cb (cls, &name, &value))
+      return false;
+  }
+  return true;
+}
+
+
+/**
+ * Process request-target string, form URI and URI parameters
+ * @param c the connection to process
+ * @return true if request-target successfully processed,
+ *         false if error encountered
+ */
+static MHD_FN_PAR_NONNULL_ALL_ bool
+process_request_target (struct MHD_Connection *c)
+{
+#ifdef _DEBUG
+  size_t params_len;
+#endif /* _DEBUG */
+  mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+  mhd_assert (NULL == c->rq.url);
+  mhd_assert (0 == c->rq.url_len);
+  mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
+  mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+              (c->rq.hdrs.rq_line.rq_tgt <= c->rq.hdrs.rq_line.rq_tgt_qmark));
+  mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+              (c->rq.req_target_len > \
+               (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark \
+                         - c->rq.hdrs.rq_line.rq_tgt)));
+
+  /* Log callback before the request-target is modified/decoded */
+  if (NULL != c->daemon->req_cfg.uri_cb.cb)
+  {
+    struct MHD_String full_uri;
+    full_uri.cstr = c->rq.hdrs.rq_line.rq_tgt;
+    full_uri.len = c->rq.req_target_len;
+    c->rq.client_aware = true;
+    c->daemon->req_cfg.uri_cb.cb (c->daemon->req_cfg.uri_cb.cls,
+                                  &(c->rq),
+                                  &full_uri);
+  }
+
+  if (NULL != c->rq.hdrs.rq_line.rq_tgt_qmark)
+  {
+    params_len =
+      c->rq.req_target_len
+      - (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark - c->rq.hdrs.rq_line.rq_tgt);
+
+    mhd_assert (1 <= params_len);
+
+    c->rq.hdrs.rq_line.rq_tgt_qmark[0] = 0; /* Replace '?' with zero 
termination */
+
+    // TODO: support detection of decoding errors
+    if (! mhd_parse_get_args (params_len - 1,
+                              c->rq.hdrs.rq_line.rq_tgt_qmark + 1,
+                              &request_add_get_arg,
+                              c))
+    {
+      MHD_LOG_MSG (c->daemon, MHD_SC_CONNECTION_POOL_NO_MEM_GET_PARAM,
+                   "Not enough memory in the pool to store GET parameter");
+
+      mhd_RESPOND_WITH_ERROR_STATIC (
+        c,
+        mhd_stream_get_no_space_err_status_code (c,MHD_PROC_RECV_URI, 0, NULL),
+        ERR_RSP_MSG_REQUEST_TOO_BIG);
+      mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING != c->state);
+      return false;
+
+    }
+  }
+  else
+    params_len = 0;
+
+  mhd_assert (strlen (c->rq.hdrs.rq_line.rq_tgt) == \
+              c->rq.req_target_len - params_len);
+
+  /* Finally unescape URI itself */
+  // TODO: support detection of decoding errors
+  c->rq.url_len =
+    mhd_str_pct_decode_lenient_n (c->rq.hdrs.rq_line.rq_tgt,
+                                  c->rq.req_target_len - params_len,
+                                  c->rq.hdrs.rq_line.rq_tgt,
+                                  c->rq.req_target_len - params_len,
+                                  NULL);
+  c->rq.url = c->rq.hdrs.rq_line.rq_tgt;
+
+  return true;
+}
+
+
+#ifndef MHD_MAX_FIXED_URI_LEN
+/**
+ * The maximum size of the fixed URI for automatic redirection
+ */
+#define MHD_MAX_FIXED_URI_LEN (64 * 1024)
+#endif /* ! MHD_MAX_FIXED_URI_LEN */
+
+/**
+ * Send the automatic redirection to fixed URI when received URI with
+ * whitespaces.
+ * If URI is too large, close connection with error.
+ *
+ * @param c the connection to process
+ */
+static void
+send_redirect_fixed_rq_target (struct MHD_Connection *restrict c)
+{
+  char *b;
+  size_t fixed_uri_len;
+  size_t i;
+  size_t o;
+  char *hdr_name;
+  size_t hdr_name_len;
+
+  mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+  mhd_assert (0 != c->rq.hdrs.rq_line.num_ws_in_uri);
+  mhd_assert (c->rq.hdrs.rq_line.num_ws_in_uri <= \
+              c->rq.req_target_len);
+  fixed_uri_len = c->rq.req_target_len
+                  + 2 * c->rq.hdrs.rq_line.num_ws_in_uri;
+  if ( (fixed_uri_len + 200 > c->daemon->conns.cfg.mem_pool_size) ||
+       (fixed_uri_len > MHD_MAX_FIXED_URI_LEN) ||
+       (NULL == (b = malloc (fixed_uri_len + 1))) )
+  {
+    mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR, \
+                      "The request has whitespace character is " \
+                      "in the URI and the URI is too large to " \
+                      "send automatic redirect to fixed URI.");
+    return;
+  }
+  i = 0;
+  o = 0;
+
+  do
+  {
+    const char chr = c->rq.hdrs.rq_line.rq_tgt[i++];
+
+    mhd_assert ('\r' != chr); /* Replaced during request line parsing */
+    mhd_assert ('\n' != chr); /* Rejected during request line parsing */
+    mhd_assert (0 != chr); /* Rejected during request line parsing */
+    switch (chr)
+    {
+    case ' ':
+      b[o++] = '%';
+      b[o++] = '2';
+      b[o++] = '0';
+      break;
+    case '\t':
+      b[o++] = '%';
+      b[o++] = '0';
+      b[o++] = '9';
+      break;
+    case 0x0B:   /* VT (vertical tab) */
+      b[o++] = '%';
+      b[o++] = '0';
+      b[o++] = 'B';
+      break;
+    case 0x0C:   /* FF (form feed) */
+      b[o++] = '%';
+      b[o++] = '0';
+      b[o++] = 'C';
+      break;
+    default:
+      b[o++] = chr;
+      break;
+    }
+  } while (i < c->rq.req_target_len);
+  mhd_assert (fixed_uri_len == o);
+  b[o] = 0; /* Zero-terminate the result */
+
+  hdr_name_len = mhd_SSTR_LEN (MHD_HTTP_HEADER_LOCATION);
+  hdr_name = malloc (hdr_name_len + 1);
+  if (NULL != hdr_name)
+  {
+    memcpy (hdr_name,
+            MHD_HTTP_HEADER_LOCATION,
+            hdr_name_len + 1);
+    /* hdr_name and b are free()d within this call */
+    mhd_RESPOND_WITH_ERROR_HEADER (c,
+                                   MHD_HTTP_STATUS_MOVED_PERMANENTLY,
+                                   ERR_RSP_RQ_TARGET_INVALID_CHAR,
+                                   hdr_name_len,
+                                   hdr_name,
+                                   o,
+                                   b);
+    return;
+  }
+  free (b);
+  mhd_STREAM_ABORT (c, mhd_STREAM_ABORT_CLIENT_HTTP_ERR,
+                    "The request has whitespace character is in the URI.");
+  return;
+}
+
+
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
-mhd_get_request_line (struct MHD_Connection *restrict c)
+mhd_stream_get_request_line (struct MHD_Connection *restrict c)
 {
   const int discp_lvl = c->daemon->req_cfg.strictnees;
   /* Parse whitespace in URI, special parsing of the request line */
@@ -918,9 +1354,9 @@ mhd_get_request_line (struct MHD_Connection *restrict c)
           - (size_t) (c->rq.version - c->read_buffer))))
     {
       c->rq.http_ver = MHD_HTTP_VERSION_INVALID;
-      transmit_error_response_static (c,
-                                      MHD_HTTP_STATUS_BAD_REQUEST,
-                                      ERR_RSP_REQUEST_MALFORMED);
+      mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                     MHD_HTTP_STATUS_BAD_REQUEST,
+                                     ERR_RSP_REQUEST_MALFORMED);
       return true; /* Error in the request */
     }
     return false;
@@ -936,9 +1372,9 @@ mhd_get_request_line (struct MHD_Connection *restrict c)
   {
     if (! wsp_in_uri)
     {
-      transmit_error_response_static (c,
-                                      MHD_HTTP_STATUS_BAD_REQUEST,
-                                      ERR_RSP_RQ_TARGET_INVALID_CHAR);
+      mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                     MHD_HTTP_STATUS_BAD_REQUEST,
+                                     ERR_RSP_RQ_TARGET_INVALID_CHAR);
       return true; /* Error in the request */
     }
     if (! wsp_in_uri_keep)
@@ -956,13 +1392,14 @@ mhd_get_request_line (struct MHD_Connection *restrict c)
 
 
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_switch_to_rq_headers_processing (struct MHD_Connection *restrict c)
+mhd_stream_switch_to_rq_headers_proc (struct MHD_Connection *restrict c)
 {
   c->rq.field_lines.start = c->read_buffer;
-  memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
+  mhd_stream_reset_rq_hdr_proc_state (c);
   c->state = MHD_CONNECTION_REQ_HEADERS_RECEIVING;
 }
 
+
 /**
  * Send error reply when receive buffer space exhausted while receiving or
  * storing the request headers
@@ -973,27 +1410,55 @@ mhd_switch_to_rq_headers_processing (struct 
MHD_Connection *restrict c)
  *                   Can be NULL.
  * @param add_header_size the size of the @a add_header
  */
-static void
+MHD_static_inline_
+MHD_FN_PAR_NONNULL_ (1) void
 handle_req_headers_no_space (struct MHD_Connection *restrict c,
                              const char *restrict add_header,
                              size_t add_header_size)
 {
   unsigned int err_code;
 
-  err_code = get_no_space_err_status_code (c,
-                                           MHD_PROC_RECV_HEADERS,
-                                           add_header,
-                                           add_header_size);
-  transmit_error_response_static (c,
-                                  err_code,
-                                  ERR_RSP_REQUEST_HEADER_TOO_BIG);
+  err_code = mhd_stream_get_no_space_err_status_code (c,
+                                                      MHD_PROC_RECV_HEADERS,
+                                                      add_header_size,
+                                                      add_header);
+  mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                 err_code,
+                                 ERR_RSP_REQUEST_HEADER_TOO_BIG);
+}
+
+
+/**
+ * Send error reply when receive buffer space exhausted while receiving or
+ * storing the request footers (for chunked requests).
+ * @param c the connection to handle
+ * @param add_footer the optional pointer to the current footer string being
+ *                   processed or the footer failed to be added.
+ *                   Could be not zero-terminated and can contain binary zeros.
+ *                   Can be NULL.
+ * @param add_footer_size the size of the @a add_footer
+ */
+MHD_static_inline_
+MHD_FN_PAR_NONNULL_ (1) void
+handle_req_footers_no_space (struct MHD_Connection *restrict c,
+                             const char *restrict add_footer,
+                             size_t add_footer_size)
+{
+  (void) add_footer; (void) add_footer_size; /* Unused */
+  mhd_assert (c->rq.have_chunked_upload);
+
+  /* Footers should be optional */
+  mhd_RESPOND_WITH_ERROR_STATIC (
+    c,
+    MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
+    ERR_RSP_REQUEST_FOOTER_TOO_BIG);
 }
 
 
 /**
  * Results of header line reading
  */
-enum mhd_HdrLineReadRes
+enum MHD_FIXED_ENUM_ mhd_HdrLineReadRes
 {
   /**
    * Not enough data yet
@@ -1011,7 +1476,7 @@ enum mhd_HdrLineReadRes
    * Found the end of the request header (end of field lines)
    */
   MHD_HDR_LINE_READING_GOT_END_OF_HEADER
-} _MHD_FIXED_ENUM;
+};
 
 
 /**
@@ -1022,10 +1487,9 @@ enum mhd_HdrLineReadRes
  *                        if false then headers are processed
  * @param[out] hdr_name the name of the parsed header (field)
  * @param[out] hdr_name the value of the parsed header (field)
- * @return true if request header line completely processed,
- *         false if not enough data yet in the receive buffer
+ * @return mhd_HdrLineReadRes value
  */
-static enum MHD_HdrLineReadRes_
+static enum mhd_HdrLineReadRes
 get_req_header (struct MHD_Connection *restrict c,
                 bool process_footers,
                 struct MHD_String *restrict hdr_name,
@@ -1133,13 +1597,13 @@ get_req_header (struct MHD_Connection *restrict c,
         else if (! bare_cr_keep)
         {
           if (! process_footers)
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_BARE_CR_IN_HEADER);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_BARE_CR_IN_HEADER);
           else
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_BARE_CR_IN_FOOTER);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_BARE_CR_IN_FOOTER);
           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
         }
         end_of_line = false;
@@ -1162,13 +1626,13 @@ get_req_header (struct MHD_Connection *restrict c,
       else
       {
         if (! process_footers)
-          transmit_error_response_static (c,
-                                          MHD_HTTP_STATUS_BAD_REQUEST,
-                                          ERR_RSP_BARE_LF_IN_HEADER);
+          mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                         MHD_HTTP_STATUS_BAD_REQUEST,
+                                         ERR_RSP_BARE_LF_IN_HEADER);
         else
-          transmit_error_response_static (c,
-                                          MHD_HTTP_STATUS_BAD_REQUEST,
-                                          ERR_RSP_BARE_LF_IN_FOOTER);
+          mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                         MHD_HTTP_STATUS_BAD_REQUEST,
+                                         ERR_RSP_BARE_LF_IN_FOOTER);
         return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
       }
     }
@@ -1213,13 +1677,13 @@ get_req_header (struct MHD_Connection *restrict c,
         if (! allow_folded)
         {
           if (! process_footers)
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_OBS_FOLD);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_OBS_FOLD);
           else
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_OBS_FOLD_FOOTER);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_OBS_FOLD_FOOTER);
 
           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
         }
@@ -1252,13 +1716,13 @@ get_req_header (struct MHD_Connection *restrict c,
           if (! allow_line_without_colon)
           {
             if (! process_footers)
-              transmit_error_response_static (c,
-                                              MHD_HTTP_STATUS_BAD_REQUEST,
-                                              ERR_RSP_HEADER_WITHOUT_COLON);
+              mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                             MHD_HTTP_STATUS_BAD_REQUEST,
+                                             ERR_RSP_HEADER_WITHOUT_COLON);
             else
-              transmit_error_response_static (c,
-                                              MHD_HTTP_STATUS_BAD_REQUEST,
-                                              ERR_RSP_FOOTER_WITHOUT_COLON);
+              mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                             MHD_HTTP_STATUS_BAD_REQUEST,
+                                             ERR_RSP_FOOTER_WITHOUT_COLON);
 
             return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
           }
@@ -1325,13 +1789,13 @@ get_req_header (struct MHD_Connection *restrict c,
         if (! allow_wsp_at_start)
         {
           if (! process_footers)
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_WSP_BEFORE_HEADER);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_WSP_BEFORE_HEADER);
           else
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_WSP_BEFORE_FOOTER);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_WSP_BEFORE_FOOTER);
           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
         }
         c->rq.hdrs.hdr.starts_with_ws = true;
@@ -1348,13 +1812,13 @@ get_req_header (struct MHD_Connection *restrict c,
         else
         {
           if (! process_footers)
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_WSP_IN_HEADER_NAME);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_WSP_IN_HEADER_NAME);
           else
-            transmit_error_response_static (c,
-                                            MHD_HTTP_STATUS_BAD_REQUEST,
-                                            ERR_RSP_WSP_IN_FOOTER_NAME);
+            mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                           MHD_HTTP_STATUS_BAD_REQUEST,
+                                           ERR_RSP_WSP_IN_FOOTER_NAME);
 
           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
         }
@@ -1371,13 +1835,13 @@ get_req_header (struct MHD_Connection *restrict c,
       if (! nul_as_sp)
       {
         if (! process_footers)
-          transmit_error_response_static (c,
-                                          MHD_HTTP_STATUS_BAD_REQUEST,
-                                          ERR_RSP_INVALID_CHR_IN_HEADER);
+          mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                         MHD_HTTP_STATUS_BAD_REQUEST,
+                                         ERR_RSP_INVALID_CHR_IN_HEADER);
         else
-          transmit_error_response_static (c,
-                                          MHD_HTTP_STATUS_BAD_REQUEST,
-                                          ERR_RSP_INVALID_CHR_IN_FOOTER);
+          mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                         MHD_HTTP_STATUS_BAD_REQUEST,
+                                         ERR_RSP_INVALID_CHR_IN_FOOTER);
 
         return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
       }
@@ -1404,13 +1868,13 @@ get_req_header (struct MHD_Connection *restrict c,
             if (! allow_wsp_before_colon)
             {
               if (! process_footers)
-                transmit_error_response_static (c,
-                                                MHD_HTTP_STATUS_BAD_REQUEST,
-                                                ERR_RSP_WSP_IN_HEADER_NAME);
+                mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                               MHD_HTTP_STATUS_BAD_REQUEST,
+                                               ERR_RSP_WSP_IN_HEADER_NAME);
               else
-                transmit_error_response_static (c,
-                                                MHD_HTTP_STATUS_BAD_REQUEST,
-                                                ERR_RSP_WSP_IN_FOOTER_NAME);
+                mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                               MHD_HTTP_STATUS_BAD_REQUEST,
+                                               ERR_RSP_WSP_IN_FOOTER_NAME);
               return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request 
*/
             }
             c->rq.hdrs.hdr.name_len = c->rq.hdrs.hdr.ws_start;
@@ -1421,13 +1885,13 @@ get_req_header (struct MHD_Connection *restrict c,
           if ((0 == c->rq.hdrs.hdr.name_len) && ! allow_empty_name)
           {
             if (! process_footers)
-              transmit_error_response_static (c,
-                                              MHD_HTTP_STATUS_BAD_REQUEST,
-                                              ERR_RSP_EMPTY_HEADER_NAME);
+              mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                             MHD_HTTP_STATUS_BAD_REQUEST,
+                                             ERR_RSP_EMPTY_HEADER_NAME);
             else
-              transmit_error_response_static (c,
-                                              MHD_HTTP_STATUS_BAD_REQUEST,
-                                              ERR_RSP_EMPTY_FOOTER_NAME);
+              mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                             MHD_HTTP_STATUS_BAD_REQUEST,
+                                             ERR_RSP_EMPTY_FOOTER_NAME);
             return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
           }
           c->rq.hdrs.hdr.name_end_found = true;
@@ -1442,13 +1906,13 @@ get_req_header (struct MHD_Connection *restrict c,
             if (! allow_wsp_in_name)
             {
               if (! process_footers)
-                transmit_error_response_static (c,
-                                                MHD_HTTP_STATUS_BAD_REQUEST,
-                                                ERR_RSP_WSP_IN_HEADER_NAME);
+                mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                               MHD_HTTP_STATUS_BAD_REQUEST,
+                                               ERR_RSP_WSP_IN_HEADER_NAME);
               else
-                transmit_error_response_static (c,
-                                                MHD_HTTP_STATUS_BAD_REQUEST,
-                                                ERR_RSP_WSP_IN_FOOTER_NAME);
+                mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                               MHD_HTTP_STATUS_BAD_REQUEST,
+                                               ERR_RSP_WSP_IN_FOOTER_NAME);
 
               return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request 
*/
             }
@@ -1478,8 +1942,23 @@ get_req_header (struct MHD_Connection *restrict c,
 }
 
 
+/**
+ * Reset request header processing state.
+ *
+ * This function resets the processing state before processing the next header
+ * (or footer) line.
+ * @param c the connection to process
+ */
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_stream_reset_rq_hdr_proc_state (struct MHD_Connection *c)
+{
+  memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
+}
+
+
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
-mhd_get_req_headers (struct MHD_Connection *restrict c, bool process_footers)
+mhd_stream_get_request_headers (struct MHD_Connection *restrict c,
+                                bool process_footers)
 {
   do
   {
@@ -1530,7 +2009,7 @@ mhd_get_req_headers (struct MHD_Connection *restrict c, 
bool process_footers)
 
         mhd_assert (hdr_name.cstr < hdr_value.cstr);
 
-        if (!process_footers)
+        if (! process_footers)
           MHD_LOG_MSG (c->daemon, MHD_SC_CONNECTION_POOL_MALLOC_FAILURE_REQ, \
                        "Failed to allocate memory in the connection memory " \
                        "pool to store header.");
@@ -1551,7 +2030,7 @@ mhd_get_req_headers (struct MHD_Connection *restrict c, 
bool process_footers)
         return true;
       }
       /* Reset processing state */
-      reset_rq_header_processing_state (c);
+      mhd_stream_reset_rq_hdr_proc_state (c);
       mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
                    MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
                   c->state);
@@ -1593,15 +2072,15 @@ mhd_get_req_headers (struct MHD_Connection *restrict c, 
bool process_footers)
   {
     if (! process_footers)
       MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
-                     MHD_LOG_FMT("%" PRIuFAST64 " bare CR characters have " \
-                                 "been replaced with spaces in the request " \
-                                 "line and/or in the request headers."), \
+                     MHD_LOG_FMT ("%" PRIuFAST64 " bare CR characters have " \
+                                  "been replaced with spaces in the request " \
+                                  "line and/or in the request headers."), \
                      (uint_fast64_t) c->rq.num_cr_sp_replaced);
     else
       MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
-                     MHD_LOG_FMT("%" PRIuFAST64 " bare CR characters have " \
-                                 "been replaced with spaces in the request " \
-                                 "footers."), \
+                     MHD_LOG_FMT ("%" PRIuFAST64 " bare CR characters have " \
+                                  "been replaced with spaces in the request " \
+                                  "footers."), \
                      (uint_fast64_t) c->rq.num_cr_sp_replaced);
 
 
@@ -1619,13 +2098,13 @@ mhd_get_req_headers (struct MHD_Connection *restrict c, 
bool process_footers)
   {
     if (! process_footers)
       MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
-                     MHD_LOG_FMT("%" PRIu64 " header lines without colons "
-                                 "have been skipped."),
+                     MHD_LOG_FMT ("%" PRIu64 " header lines without colons "
+                                  "have been skipped."),
                      (uint_fast64_t) c->rq.skipped_broken_lines);
     else
       MHD_LOG_PRINT (c->daemon, MHD_SC_REQ_HEADER_CR_REPLACED, \
-                     MHD_LOG_FMT("%" PRIu64 " footer lines without colons "
-                                 "have been skipped."),
+                     MHD_LOG_FMT ("%" PRIu64 " footer lines without colons "
+                                  "have been skipped."),
                      (uint_fast64_t) c->rq.skipped_broken_lines);
   }
 
@@ -1652,7 +2131,7 @@ mhd_get_req_headers (struct MHD_Connection *restrict c, 
bool process_footers)
       const char *last_elmnt_end;
       size_t shift_back_size;
       struct mhd_RequestField *header;
-      header = mhd_DLINKEDL_GET_LAST(&(c->rq), fields);
+      header = mhd_DLINKEDL_GET_LAST (&(c->rq), fields);
       if (NULL != header)
         last_elmnt_end =
           header->field.nv.value.cstr + header->field.nv.value.len;
@@ -1701,8 +2180,9 @@ enum _MHD_ParseCookie
  * @param connection the connection to add parsed cookies
  * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
  */
-static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_(2)
-MHD_FN_PAR_INOUT_SIZE_(2,1) enum _MHD_ParseCookie
+static MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_CSTR_ (2)
+MHD_FN_PAR_INOUT_SIZE_ (2,1) enum _MHD_ParseCookie
 parse_cookies_string (const size_t str_len,
                       char *restrict str,
                       struct MHD_Connection *restrict connection)
@@ -1848,10 +2328,10 @@ parse_cookies_string (const size_t str_len,
       str[value_start + value_len] = 0; /* Zero-terminate the value */
       value.cstr = str + value_start;
       value.len = value_len;
-      if (! mhd_stream_add_field(connection,
-                                 MHD_VK_COOKIE,
-                                 &name,
-                                 &value))
+      if (! mhd_stream_add_field (connection,
+                                  MHD_VK_COOKIE,
+                                  &name,
+                                  &value))
         return MHD_PARSE_COOKIE_NO_MEMORY;
     }
     else
@@ -1860,12 +2340,12 @@ parse_cookies_string (const size_t str_len,
       struct MHD_String value;
       name.cstr = str + name_start;
       name.len = name_len;
-      value.cstr = ""
+      value.cstr = "";
       value.len = 0;
-      if (! mhd_stream_add_field(connection,
-                                 MHD_VK_COOKIE,
-                                 &name,
-                                 &value))
+      if (! mhd_stream_add_field (connection,
+                                  MHD_VK_COOKIE,
+                                  &name,
+                                  &value))
         return MHD_PARSE_COOKIE_NO_MEMORY;
     }
     if (str_len > i)
@@ -1911,20 +2391,19 @@ parse_cookies_string (const size_t str_len,
  * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
  */
 static enum _MHD_ParseCookie
-parse_cookie_header (struct MHD_Connection *connection)
+parse_cookie_header (struct MHD_Connection *restrict connection)
 {
-  struct MHD_String *hvalue;
+  const struct MHD_StringNullable *hvalue;
   char *cpy;
   size_t i;
   enum _MHD_ParseCookie parse_res;
   struct mhd_RequestField *const saved_tail =
-    connection->rq.fields.last;
+    connection->rq.fields.last;  // FIXME: a better way?
   const bool allow_partially_correct_cookie =
     (1 >= connection->daemon->req_cfg.strictnees);
 
-  hvalue = mhd_request_get_value_len(&(connection->rq),
+  hvalue = mhd_request_get_value_st (&(connection->rq),
                                      MHD_VK_HEADER,
-                                     mhd_SSTR_LEN (MHD_HTTP_HEADER_COOKIE),
                                      MHD_HTTP_HEADER_COOKIE);
   if (NULL == hvalue)
     return MHD_PARSE_COOKIE_OK;
@@ -1938,16 +2417,16 @@ parse_cookie_header (struct MHD_Connection *connection)
   else
   {
     memcpy (cpy,
-            hdr,
-            hdr_len);
-    cpy[hdr_len] = '\0';
+            hvalue->cstr,
+            hvalue->len + 1);
+    mhd_assert (0 == cpy[hvalue->len]);
 
-    i = 0;
-    /* Skip all initial whitespaces */
-    while (i < hdr_len && (' ' == cpy[i] || '\t' == cpy[i]))
-      i++;
+    /* Must not have initial whitespaces */
+    mhd_assert (' ' != cpy[0]);
+    mhd_assert ('\t' != cpy[0]);
 
-    parse_res = parse_cookies_string (cpy + i, hdr_len - i, connection);
+    i = 0;
+    parse_res = parse_cookies_string (hvalue->len - i, cpy + i, connection);
   }
 
   switch (parse_res)
@@ -1955,96 +2434,101 @@ parse_cookie_header (struct MHD_Connection *connection)
   case MHD_PARSE_COOKIE_OK:
     break;
   case MHD_PARSE_COOKIE_OK_LAX:
-#ifdef HAVE_MESSAGES
-    if (saved_tail != connection->rq.headers_received_tail)
-      MHD_DLOG (connection->daemon,
-                _ ("The Cookie header has been parsed, but it is not fully "
-                   "compliant with the standard.\n"));
-#endif /* HAVE_MESSAGES */
+    if (saved_tail != connection->rq.fields.last)
+      MHD_LOG_MSG (connection->daemon, MHD_SC_REQ_COOKIE_PARSED_NOT_COMPLIANT, 
\
+                   "The Cookie header has been parsed, but it is not "
+                   "fully compliant with specifications.");
     break;
   case MHD_PARSE_COOKIE_MALFORMED:
-    if (saved_tail != connection->rq.headers_received_tail)
+    if (saved_tail != connection->rq.fields.last) // FIXME: a better way?
     {
       if (! allow_partially_correct_cookie)
       {
         /* Remove extracted values from partially broken cookie */
         /* Memory remains allocated until the end of the request processing */
-        connection->rq.headers_received_tail = saved_tail;
-        saved_tail->next = NULL;
-#ifdef HAVE_MESSAGES
-        MHD_DLOG (connection->daemon,
-                  _ ("The Cookie header has been ignored as it contains "
-                     "malformed data.\n"));
-#endif /* HAVE_MESSAGES */
+        connection->rq.fields.last = saved_tail;  // FIXME: a better way?
+        saved_tail->fields.next = NULL;  // FIXME: a better way?
+        MHD_LOG_MSG ( \
+          connection->daemon, MHD_SC_REQ_COOKIE_IGNORED_NOT_COMPLIANT, \
+          "The Cookie header is ignored as it contains malformed data.");
       }
-#ifdef HAVE_MESSAGES
       else
-        MHD_DLOG (connection->daemon,
-                  _ ("The Cookie header has been only partially parsed as it "
-                     "contains malformed data.\n"));
-#endif /* HAVE_MESSAGES */
+        MHD_LOG_MSG (connection->daemon, MHD_SC_REQ_COOKIE_PARSED_PARTIALLY, \
+                     "The Cookie header has been only partially parsed " \
+                     "as it contains malformed data.");
     }
-#ifdef HAVE_MESSAGES
     else
-      MHD_DLOG (connection->daemon,
-                _ ("The Cookie header has malformed data.\n"));
-#endif /* HAVE_MESSAGES */
+      MHD_LOG_MSG (connection->daemon, MHD_SC_REQ_COOKIE_INVALID,
+                   "The Cookie header has malformed data.");
     break;
   case MHD_PARSE_COOKIE_NO_MEMORY:
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (connection->daemon,
-              _ ("Not enough memory in the connection pool to "
-                 "parse client cookies!\n"));
-#endif /* HAVE_MESSAGES */
+    MHD_LOG_MSG (connection->daemon, MHD_SC_CONNECTION_POOL_NO_MEM_COOKIE,
+                 "Not enough memory in the connection pool to "
+                 "parse client cookies!\n");
     break;
   default:
-    mhd_assert (0);
+    mhd_assert (0 && "Impossible value");
+    MHD_UNREACHABLE_;
     break;
   }
-#ifndef HAVE_MESSAGES
-  (void) saved_tail; /* Mute compiler warning */
-#endif /* ! HAVE_MESSAGES */
 
   return parse_res;
 }
 
 
-#endif /* COOKIE_SUPPORT */
+/**
+ * Send error reply when receive buffer space exhausted while receiving or
+ * storing the request headers
+ * @param c the connection to handle
+ * @param add_header the optional pointer to the current header string being
+ *                   processed or the header failed to be added.
+ *                   Could be not zero-terminated and can contain binary zeros.
+ *                   Can be NULL.
+ * @param add_header_size the size of the @a add_header
+ */
+MHD_static_inline_ void
+handle_req_cookie_no_space (struct MHD_Connection *restrict c)
+{
+  unsigned int err_code;
 
+  err_code = mhd_stream_get_no_space_err_status_code (c,
+                                                      MHD_PROC_RECV_COOKIE,
+                                                      0,
+                                                      NULL);
+  mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                 err_code,
+                                 ERR_RSP_REQUEST_HEADER_TOO_BIG);
+}
+
+
+#endif /* COOKIE_SUPPORT */
 
 
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
-mhd_parse_connection_headers (struct MHD_Connection *restrict c)
+mhd_stream_parse_connection_headers (struct MHD_Connection *restrict c)
 {
-  const char *clen;
-  const char *enc;
-  size_t val_len;
+  const struct MHD_StringNullable *hcntnlen;
+  const struct MHD_StringNullable *htrenc;
 
 #ifdef COOKIE_SUPPORT
-  if (MHD_PARSE_COOKIE_NO_MEMORY == parse_cookie_header (connection))
+  if (MHD_PARSE_COOKIE_NO_MEMORY == parse_cookie_header (c))
   {
-    handle_req_cookie_no_space (connection);
+    handle_req_cookie_no_space (c);
     return;
   }
 #endif /* COOKIE_SUPPORT */
-  if ( (-3 < connection->daemon->client_discipline) &&
-       (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) &&
-       (MHD_NO ==
-        MHD_lookup_connection_value_n (connection,
-                                       MHD_VK_HEADER,
-                                       MHD_HTTP_HEADER_HOST,
-                                       mhd_SSTR_LEN (
-                                         MHD_HTTP_HEADER_HOST),
-                                       NULL,
-                                       NULL)) )
+
+  if ( (-3 < c->daemon->req_cfg.strictnees) &&
+       (MHD_HTTP_VERSION_1_1 == c->rq.http_ver) &&
+       (NULL == mhd_request_get_value_st (&(c->rq),
+                                          MHD_VK_HEADER,
+                                          MHD_HTTP_HEADER_HOST)))
   {
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (connection->daemon,
-              _ ("Received HTTP/1.1 request without `Host' header.\n"));
-#endif
-    transmit_error_response_static (connection,
-                                    MHD_HTTP_STATUS_BAD_REQUEST,
-                                    REQUEST_LACKS_HOST);
+    MHD_LOG_MSG (c->daemon, MHD_SC_HOST_HEADER_MISSING, \
+                 "Received HTTP/1.1 request without 'Host' header.");
+    mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                   MHD_HTTP_STATUS_BAD_REQUEST,
+                                   ERR_RSP_REQUEST_LACKS_HOST);
     return;
   }
 
@@ -2052,98 +2536,741 @@ mhd_parse_connection_headers (struct MHD_Connection 
*restrict c)
      "Transfer-Encoding:" request headers.
      Unless one of these two headers is used, the request has no request body.
      See RFC9112, Section 6, paragraph 4. */
-  connection->rq.remaining_upload_size = 0;
-  if (MHD_NO !=
-      MHD_lookup_connection_value_n (connection,
+  c->rq.cntn.cntn_size = 0;
+  htrenc = mhd_request_get_value_st (&(c->rq),
                                      MHD_VK_HEADER,
-                                     MHD_HTTP_HEADER_TRANSFER_ENCODING,
-                                     mhd_SSTR_LEN (
-                                       MHD_HTTP_HEADER_TRANSFER_ENCODING),
-                                     &enc,
-                                     NULL))
+                                     MHD_HTTP_HEADER_TRANSFER_ENCODING);
+
+  if (NULL != htrenc)
   {
-    if (! MHD_str_equal_caseless_ (enc,
-                                   "chunked"))
+    if (! mhd_str_equal_caseless_n_st ("chunked", htrenc->cstr, htrenc->len))
     {
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_STATUS_BAD_REQUEST,
-                                      REQUEST_UNSUPPORTED_TR_ENCODING);
+      mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                     MHD_HTTP_STATUS_BAD_REQUEST,
+                                     ERR_RSP_UNSUPPORTED_TR_ENCODING);
       return;
     }
-    else if (MHD_NO !=
-             MHD_lookup_connection_value_n (connection,
-                                            MHD_VK_HEADER,
-                                            MHD_HTTP_HEADER_CONTENT_LENGTH,
-                                            mhd_SSTR_LEN ( \
-                                              MHD_HTTP_HEADER_CONTENT_LENGTH),
-                                            NULL,
-                                            NULL))
+
+    c->rq.have_chunked_upload = true;
+    c->rq.cntn.cntn_size = MHD_SIZE_UNKNOWN;
+
+    if (MHD_HTTP_VERSION_1_1 != c->rq.http_ver)
+      c->keepalive = MHD_CONN_MUST_CLOSE; /* Framing could in incorrect */
+  }
+
+  hcntnlen = mhd_request_get_value_st (&(c->rq),
+                                       MHD_VK_HEADER,
+                                       MHD_HTTP_HEADER_CONTENT_LENGTH);
+
+  if ((NULL != hcntnlen) && (NULL != htrenc))
+  {
+    /* TODO: add individual settings */
+    if (1 <= c->daemon->req_cfg.strictnees)
     {
-      /* TODO: add individual settings */
-      if (1 <= connection->daemon->client_discipline)
-      {
-        transmit_error_response_static (connection,
-                                        MHD_HTTP_STATUS_BAD_REQUEST,
-                                        REQUEST_LENGTH_WITH_TR_ENCODING);
-        return;
-      }
-      else
-      {
-        /* Must close connection after reply to prevent potential attack */
-        connection->keepalive = MHD_CONN_MUST_CLOSE;
-#ifdef HAVE_MESSAGES
-        MHD_DLOG (connection->daemon,
-                  _ ("The 'Content-Length' request header is ignored "
-                     "as chunked Transfer-Encoding is used "
-                     "for this request.\n"));
-#endif /* HAVE_MESSAGES */
-      }
+      mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                     MHD_HTTP_STATUS_BAD_REQUEST,
+                                     
ERR_RSP_REQUEST_CNTNLENGTH_WITH_TR_ENCODING);
+      return;
+    }
+    else
+    {
+      /* Must close connection after reply to prevent potential attack */
+      c->keepalive = MHD_CONN_MUST_CLOSE;
+      MHD_LOG_MSG (c->daemon, MHD_SC_CONTENT_LENGTH_AND_TR_ENC, \
+                   "The 'Content-Length' request header is ignored " \
+                   "as chunked Transfer-Encoding is used " \
+                   "for this request.");
     }
-    connection->rq.have_chunked_upload = true;
-    connection->rq.remaining_upload_size = MHD_SIZE_UNKNOWN;
   }
-  else if (MHD_NO !=
-           MHD_lookup_connection_value_n (connection,
-                                          MHD_VK_HEADER,
-                                          MHD_HTTP_HEADER_CONTENT_LENGTH,
-                                          mhd_SSTR_LEN (
-                                            MHD_HTTP_HEADER_CONTENT_LENGTH),
-                                          &clen,
-                                          &val_len))
+  else if (NULL != hcntnlen)
   {
     size_t num_digits;
 
-    num_digits = MHD_str_to_uint64_n_ (clen,
-                                       val_len,
-                                       &connection->rq.remaining_upload_size);
+    num_digits = mhd_str_to_uint64_n (hcntnlen->cstr,
+                                      hcntnlen->len,
+                                      &c->rq.cntn.cntn_size);
 
     if (((0 == num_digits) &&
-         (0 != val_len) &&
-         ('0' <= clen[0]) && ('9' >= clen[0]))
-        || (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size))
+         (0 != hcntnlen->len) &&
+         ('0' <= hcntnlen->cstr[0]) && ('9' >= hcntnlen->cstr[0]))
+        || (MHD_SIZE_UNKNOWN == c->rq.cntn.cntn_size))
     {
-      connection->rq.remaining_upload_size = 0;
-#ifdef HAVE_MESSAGES
-      MHD_DLOG (connection->daemon,
-                _ ("Too large value of 'Content-Length' header. " \
-                   "Closing connection.\n"));
-#endif
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
-                                      REQUEST_CONTENTLENGTH_TOOLARGE);
+      c->rq.cntn.cntn_size = 0;
+      MHD_LOG_MSG (c->daemon, MHD_SC_CONTENT_LENGTH_TOO_LARGE, \
+                   "Too large value of 'Content-Length' header. " \
+                   "Closing connection.");
+      mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                     MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+                                     ERR_RSP_REQUEST_CONTENTLENGTH_TOOLARGE);
+      return;
     }
-    else if ((val_len != num_digits) ||
+    else if ((hcntnlen->len != num_digits) ||
              (0 == num_digits))
     {
-      connection->rq.remaining_upload_size = 0;
-#ifdef HAVE_MESSAGES
-      MHD_DLOG (connection->daemon,
-                _ ("Failed to parse 'Content-Length' header. " \
-                   "Closing connection.\n"));
+      c->rq.cntn.cntn_size = 0;
+      MHD_LOG_MSG (c->daemon, MHD_SC_CONTENT_LENGTH_MALFORMED, \
+                   "Failed to parse 'Content-Length' header. " \
+                   "Closing connection.");
+      mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                     MHD_HTTP_STATUS_BAD_REQUEST,
+                                     ERR_RSP_REQUEST_CONTENTLENGTH_MALFORMED);
+      return;
+    }
+  }
+  c->state = MHD_CONNECTION_HEADERS_PROCESSED;
+  return;
+}
+
+
+/**
+ * Is "100 CONTINUE" needed to be sent for current request?
+ *
+ * @param c the connection to check
+ * @return false 100 CONTINUE is not needed,
+ *         true otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ bool
+need_100_continue (struct MHD_Connection *restrict c)
+{
+  const struct MHD_StringNullable *hvalue;
+
+  mhd_assert (MHD_HTTP_VERSION_IS_SUPPORTED (c->rq.http_ver));
+  mhd_assert (MHD_CONNECTION_BODY_RECEIVING > c->state);
+
+  if (MHD_HTTP_VERSION_1_0 == c->rq.http_ver)
+    return false;
+
+  if (0 != c->read_buffer_offset)
+    return false; /* Part of the content has been received already */
+
+  hvalue = mhd_request_get_value_st (&(c->rq),
+                                     MHD_VK_HEADER,
+                                     MHD_HTTP_HEADER_EXPECT);
+  if (NULL == hvalue)
+    return false;
+
+  if (! mhd_str_equal_caseless_n_st ("100-continue", \
+                                     hvalue->cstr, hvalue->len))
+    return false;
+
+  return true;
+}
+
+
+/**
+ * Check whether special buffer is required to handle the upload content and
+ * try to allocate if necessary.
+ * Respond with error to the client if buffer cannot be allocated
+ * @param c the connection to
+ * @return true if succeed,
+ *         false if error response is set
+ */
+static MHD_FN_PAR_NONNULL_ALL_ bool
+check_and_alloc_buf_for_upload_processing (struct MHD_Connection *restrict c)
+{
+  mhd_assert ((mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act) || \
+              (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act));
+
+  if (c->rq.have_chunked_upload)
+    return true; /* The size is unknown, buffers will be dynamically allocated
+                    and re-allocated */
+  mhd_assert (c->read_buffer_size > c->read_buffer_offset);
+#if 0 // TODO: support processing full response in the connection buffer
+  if ((c->read_buffer_size - c->read_buffer_offset) >=
+      c->rq.cntn.cntn_size)
+    return true; /* No additional buffer needed */
 #endif
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_STATUS_BAD_REQUEST,
-                                      REQUEST_CONTENTLENGTH_MALFORMED);
+
+  if ((mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act) &&
+      (NULL == c->rq.app_act.head_act.data.upload.full.cb))
+    return true; /* data will be processed only incrementally */
+
+  if (mhd_ACTION_UPLOAD != c->rq.app_act.head_act.act)
+  {
+    // TODO: add check for intermental-only POST processing */
+    mhd_assert (0 && "Not implemented yet");
+    return false;
+  }
+
+  if ((c->rq.cntn.cntn_size >
+       c->rq.app_act.head_act.data.upload.large_buffer_size) ||
+      ! mhd_daemon_get_lbuf (c->daemon, c->rq.cntn.cntn_size,
+                             &(c->rq.cntn.lbuf)))
+  {
+    if (NULL != c->rq.app_act.head_act.data.upload.inc.cb)
+    {
+      c->rq.app_act.head_act.data.upload.full.cb = NULL;
+      return true; /* Data can be processed incrementally */
     }
+
+    mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                   MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+                                   ERR_RSP_REQUEST_CONTENTLENGTH_TOOLARGE);
+    return false;
   }
+
+  return true;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
+{
+  struct MHD_Daemon *restrict d = c->daemon;
+  struct MHD_String path;
+  const struct MHD_Action *a;
+
+  mhd_assert (mhd_HTTP_METHOD_NO_METHOD != c->rq.http_mthd);
+  mhd_assert (NULL == c->rp.response);
+
+  if (mhd_ACTION_NO_ACTION != c->rq.app_act.head_act.act)
+    MHD_PANIC ("MHD_Action has been set already");
+
+  path.cstr = c->rq.url;
+  path.len = c->rq.url_len;
+
+  c->rq.client_aware = true;
+  a = d->req_cfg.cb (d->req_cfg.cb_cls,
+                     &(c->rq),
+                     &path,
+                     (enum MHD_HTTP_Method) c->rq.http_mthd,
+                     c->rq.cntn.cntn_size);
+
+  if (((NULL != a) && (&(c->rq.app_act.head_act) != a)) ||
+      ! mhd_ACTION_IS_VALID (c->rq.app_act.head_act.act))
+  {
+    MHD_LOG_MSG (d, MHD_SC_ACTION_INVALID, \
+                 "Provided action is not a correct action generated " \
+                 "for the current request.");
+    a = NULL;
+  }
+  if (NULL == a)
+    c->rq.app_act.head_act.act = mhd_ACTION_ABORT;
+
+  switch (c->rq.app_act.head_act.act)
+  {
+  case mhd_ACTION_RESPONSE:
+    c->rp.response = c->rq.app_act.head_act.data.response;
+    c->state = MHD_CONNECTION_REQ_RECV_FINISHED;
+    return true;
+  case mhd_ACTION_UPLOAD:
+    if (0 != c->rq.cntn.cntn_size)
+    {
+      if (! check_and_alloc_buf_for_upload_processing (c))
+        return true;
+      if (need_100_continue (c))
+      {
+        c->state = MHD_CONNECTION_CONTINUE_SENDING;
+        return true;
+      }
+      c->state = MHD_CONNECTION_BODY_RECEIVING;
+      return (0 != c->read_buffer_offset);
+    }
+    c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
+    return true;
+  case mhd_ACTION_POST_PROCESS:
+    mhd_assert (0 && "Not implemented yet");
+    return true;
+  case mhd_ACTION_SUSPEND:
+    c->suspended = true;
+    return false;
+  case mhd_ACTION_ABORT:
+    mhd_conn_pre_close_app_abort (c);
+    return false;
+  case mhd_ACTION_NO_ACTION:
+  default:
+    mhd_assert (0 && "Impossible value");
+    break;
+  }
+  MHD_UNREACHABLE_;
+  return false;
+}
+
+
+/**
+ * React on provided action for upload
+ * @param c the stream to use
+ * @param act the action provided by application
+ * @param final set to 'true' if this is final upload callback
+ * @return true if connection state has been changed,
+ *         false otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) bool
+process_upload_action (struct MHD_Connection *restrict c,
+                       const struct MHD_UploadAction *act,
+                       bool final)
+{
+  if (((NULL != act) && (&(c->rq.app_act.upl_act) != act)) ||
+      ! mhd_UPLOAD_ACTION_IS_VALID (c->rq.app_act.upl_act.act) ||
+      (final &&
+       (mhd_UPLOAD_ACTION_CONTINUE == c->rq.app_act.upl_act.act)))
+  {
+    MHD_LOG_MSG (c->daemon, MHD_SC_UPLOAD_ACTION_INVALID, \
+                 "Provided action is not a correct action generated " \
+                 "for the current request.");
+    act = NULL;
+  }
+  if (NULL == act)
+    c->rq.app_act.upl_act.act = mhd_UPLOAD_ACTION_ABORT;
+
+  switch (c->rq.app_act.upl_act.act)
+  {
+  case mhd_UPLOAD_ACTION_RESPONSE:
+    c->rp.response = c->rq.app_act.upl_act.data.response;
+    c->state = MHD_CONNECTION_REQ_RECV_FINISHED;
+    return true;
+  case mhd_UPLOAD_ACTION_CONTINUE:
+    memset (&(c->rq.app_act.upl_act), 0, sizeof(c->rq.app_act.upl_act));
+    return false;
+  case mhd_UPLOAD_ACTION_SUSPEND:
+    c->suspended = true;
+    return false;
+  case mhd_UPLOAD_ACTION_ABORT:
+    mhd_conn_pre_close_app_abort (c);
+    return false;
+  case mhd_UPLOAD_ACTION_NO_ACTION:
+  default:
+    mhd_assert (0 && "Impossible value");
+    break;
+  }
+  MHD_UNREACHABLE_;
+  return false;
+}
+
+
+static MHD_FN_PAR_NONNULL_ALL_ bool
+process_request_chunked_body (struct MHD_Connection *restrict c)
+{
+  struct MHD_Daemon *restrict d = c->daemon;
+  size_t available;
+  bool has_more_data;
+  char *restrict buffer_head;
+  const int discp_lvl = d->req_cfg.strictnees;
+  /* Treat bare LF as the end of the line.
+     RFC 9112, section 2.2-3
+     Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5).
+     Bare LF is processed as end of the line or rejected as broken request. */
+  const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
+  /* Allow "Bad WhiteSpace" in chunk extension.
+     RFC 9112, Section 7.1.1, Paragraph 2 */
+  const bool allow_bws = (2 < discp_lvl);
+  bool state_updated;
+
+  mhd_assert (NULL == c->rp.response);
+  mhd_assert (c->rq.have_chunked_upload);
+  mhd_assert (MHD_SIZE_UNKNOWN == c->rq.cntn.cntn_size);
+
+  buffer_head = c->read_buffer;
+  available = c->read_buffer_offset;
+  state_updated = false;
+  do
+  {
+    size_t cntn_data_ready;
+    bool need_inc_proc;
+
+    has_more_data = false;
+
+    if ( (c->rq.current_chunk_offset ==
+          c->rq.current_chunk_size) &&
+         (0 != c->rq.current_chunk_size) )
+    {
+      size_t i;
+      mhd_assert (0 != available);
+      /* skip new line at the *end* of a chunk */
+      i = 0;
+      if ( (2 <= available) &&
+           ('\r' == buffer_head[0]) &&
+           ('\n' == buffer_head[1]) )
+        i += 2;                        /* skip CRLF */
+      else if (bare_lf_as_crlf && ('\n' == buffer_head[0]))
+        i++;                           /* skip bare LF */
+      else if (2 > available)
+        break;                         /* need more upload data */
+      if (0 == i)
+      {
+        /* malformed encoding */
+        mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                       MHD_HTTP_STATUS_BAD_REQUEST,
+                                       ERR_RSP_REQUEST_CHUNKED_MALFORMED);
+        return true;
+      }
+      available -= i;
+      buffer_head += i;
+      c->rq.current_chunk_offset = 0;
+      c->rq.current_chunk_size = 0;
+      if (0 == available)
+        break;
+    }
+    if (0 != c->rq.current_chunk_size)
+    {
+      uint_fast64_t cur_chunk_left;
+      mhd_assert (c->rq.current_chunk_offset < \
+                  c->rq.current_chunk_size);
+      /* we are in the middle of a chunk, give
+         as much as possible to the client (without
+         crossing chunk boundaries) */
+      cur_chunk_left
+        = c->rq.current_chunk_size
+          - c->rq.current_chunk_offset;
+      if (cur_chunk_left > available)
+        cntn_data_ready = available;
+      else
+      {         /* cur_chunk_left <= (size_t)available */
+        cntn_data_ready = (size_t) cur_chunk_left;
+        if (available > cntn_data_ready)
+          has_more_data = true;
+      }
+    }
+    else
+    { /* Need the parse the chunk size line */
+      /** The number of found digits in the chunk size number */
+      size_t num_dig;
+      uint_fast64_t chunk_size;
+      bool broken;
+      bool overflow;
+
+      mhd_assert (0 != available);
+
+      overflow = false;
+      chunk_size = 0; /* Mute possible compiler warning.
+                         The real value will be set later. */
+
+      num_dig = mhd_strx_to_uint64_n (buffer_head,
+                                      available,
+                                      &chunk_size);
+      mhd_assert (num_dig <= available);
+      if (num_dig == available)
+        continue; /* Need line delimiter */
+
+      broken = (0 == num_dig);
+      if (broken)
+        /* Check whether result is invalid due to uint64_t overflow */
+        overflow = ((('0' <= buffer_head[0]) && ('9' >= buffer_head[0])) ||
+                    (('A' <= buffer_head[0]) && ('F' >= buffer_head[0])) ||
+                    (('a' <= buffer_head[0]) && ('f' >= buffer_head[0])));
+      else
+      {
+        /**
+         * The length of the string with the number of the chunk size,
+         * including chunk extension
+         */
+        size_t chunk_size_line_len;
+
+        chunk_size_line_len = 0;
+        if ((';' == buffer_head[num_dig]) ||
+            (allow_bws &&
+             ((' ' == buffer_head[num_dig]) ||
+              ('\t' == buffer_head[num_dig]))))
+        { /* Chunk extension */
+          size_t i;
+
+          /* Skip bad whitespaces (if any) */
+          for (i = num_dig; i < available; ++i)
+          {
+            if ((' ' != buffer_head[i]) && ('\t' != buffer_head[i]))
+              break;
+          }
+          if (i == available)
+            break; /* need more data */
+          if (';' == buffer_head[i])
+          {
+            for (++i; i < available; ++i)
+            {
+              if ('\n' == buffer_head[i])
+                break;
+            }
+            if (i == available)
+              break; /* need more data */
+            mhd_assert (i > num_dig);
+            mhd_assert (1 <= i);
+            /* Found LF position */
+            if (bare_lf_as_crlf)
+              chunk_size_line_len = i; /* Don't care about CR before LF */
+            else if ('\r' == buffer_head[i - 1])
+              chunk_size_line_len = i;
+          }
+          else
+          { /* No ';' after "bad whitespace" */
+            mhd_assert (allow_bws);
+            mhd_assert (0 == chunk_size_line_len);
+          }
+        }
+        else
+        {
+          mhd_assert (available >= num_dig);
+          if ((2 <= (available - num_dig)) &&
+              ('\r' == buffer_head[num_dig]) &&
+              ('\n' == buffer_head[num_dig + 1]))
+            chunk_size_line_len = num_dig + 2;
+          else if (bare_lf_as_crlf &&
+                   ('\n' == buffer_head[num_dig]))
+            chunk_size_line_len = num_dig + 1;
+          else if (2 > (available - num_dig))
+            break; /* need more data */
+        }
+
+        if (0 != chunk_size_line_len)
+        { /* Valid termination of the chunk size line */
+          mhd_assert (chunk_size_line_len <= available);
+          /* Start reading payload data of the chunk */
+          c->rq.current_chunk_offset = 0;
+          c->rq.current_chunk_size = chunk_size;
+
+          available -= chunk_size_line_len;
+          buffer_head += chunk_size_line_len;
+
+          if (0 == chunk_size)
+          { /* The final (termination) chunk */
+            c->rq.cntn.cntn_size = c->rq.cntn.recv_size;
+            c->state = MHD_CONNECTION_BODY_RECEIVED;
+            state_updated = true;
+            break;
+          }
+          if (available > 0)
+            has_more_data = true;
+          continue;
+        }
+        /* Invalid chunk size line */
+      }
+
+      if (! overflow)
+        mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                       MHD_HTTP_STATUS_BAD_REQUEST,
+                                       ERR_RSP_REQUEST_CHUNKED_MALFORMED);
+      else
+        mhd_RESPOND_WITH_ERROR_STATIC (c,
+                                       MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+                                       ERR_RSP_REQUEST_CHUNK_TOO_LARGE);
+      return true;
+    }
+    mhd_assert (c->rq.client_aware);
+
+    if (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act)
+    {
+      mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
+      return false;
+    }
+
+    if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
+    {
+      need_inc_proc = false;
+
+      mhd_assert (0 == c->rq.cntn.proc_size);
+      if ((uint_fast64_t) c->rq.cntn.lbuf.size <
+          c->rq.cntn.recv_size + cntn_data_ready)
+      {
+        size_t grow_size;
+
+        grow_size = (size_t) (c->rq.cntn.recv_size + cntn_data_ready
+                              - c->rq.cntn.lbuf.size);
+        if (((size_t) (c->rq.cntn.recv_size + cntn_data_ready) <
+             cntn_data_ready) || (! mhd_daemon_grow_lbuf (d,
+                                                          grow_size,
+                                                          &(c->rq.cntn.lbuf))))
+        {
+          /* Failed to grow the buffer, no space to put the new data */
+          const struct MHD_UploadAction *act;
+          if (NULL != c->rq.app_act.head_act.data.upload.inc.cb)
+          {
+            mhd_RESPOND_WITH_ERROR_STATIC (
+              c,
+              MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
+              ERR_RSP_MSG_REQUEST_TOO_BIG);
+            return true;
+          }
+          c->rq.app_act.head_act.data.upload.full.cb = NULL; /* Cannot process 
"full" content */
+          /* Process previously buffered data */
+          mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
+          act = c->rq.app_act.head_act.data.upload.inc.cb (
+            c->rq.app_act.head_act.data.upload.inc.cls,
+            &(c->rq),
+            c->rq.cntn.recv_size,
+            c->rq.cntn.lbuf.buf);
+          c->rq.cntn.proc_size = c->rq.cntn.recv_size;
+          mhd_daemon_free_lbuf (d, &(c->rq.cntn.lbuf));
+          if (process_upload_action (c, act, false))
+            return true;
+          need_inc_proc = true;
+        }
+      }
+      if (! need_inc_proc)
+      {
+        memcpy (c->rq.cntn.lbuf.buf + c->rq.cntn.recv_size,
+                buffer_head, cntn_data_ready);
+        c->rq.cntn.recv_size += cntn_data_ready;
+      }
+    }
+    else
+      need_inc_proc = true;
+
+    if (need_inc_proc)
+    {
+      const struct MHD_UploadAction *act;
+      mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
+
+      c->rq.cntn.recv_size += cntn_data_ready;
+      act = c->rq.app_act.head_act.data.upload.inc.cb (
+        c->rq.app_act.head_act.data.upload.inc.cls,
+        &(c->rq),
+        cntn_data_ready,
+        buffer_head);
+      c->rq.cntn.proc_size += cntn_data_ready;
+      state_updated = process_upload_action (c, act, false);
+    }
+
+    /* dh left "processed" bytes in buffer for next time... */
+    buffer_head += cntn_data_ready;
+    available -= cntn_data_ready;
+    mhd_assert (MHD_SIZE_UNKNOWN == c->rq.cntn.cntn_size);
+    c->rq.current_chunk_offset += cntn_data_ready;
+  } while (has_more_data && ! state_updated);
+  /* TODO: optionally? zero out reused memory region */
+  if ( (available > 0) &&
+       (buffer_head != c->read_buffer) )
+    memmove (c->read_buffer,
+             buffer_head,
+             available);
+  else
+    mhd_assert ((0 == available) || \
+                (c->read_buffer_offset == available));
+  c->read_buffer_offset = available;
+
+  return state_updated;
+}
+
+
+static MHD_FN_PAR_NONNULL_ALL_ bool
+process_request_nonchunked_body (struct MHD_Connection *restrict c)
+{
+  size_t cntn_data_ready;
+  bool read_buf_reuse;
+  bool state_updated;
+
+  mhd_assert (NULL == c->rp.response);
+  mhd_assert (! c->rq.have_chunked_upload);
+  mhd_assert (MHD_SIZE_UNKNOWN != c->rq.cntn.cntn_size);
+  mhd_assert (c->rq.cntn.recv_size < c->rq.cntn.cntn_size);
+  mhd_assert (c->rq.client_aware);
+
+  if ((c->rq.cntn.cntn_size - c->rq.cntn.recv_size) < c->read_buffer_offset)
+    cntn_data_ready = (size_t) (c->rq.cntn.cntn_size - c->rq.cntn.recv_size);
+  else
+    cntn_data_ready = c->read_buffer_offset;
+
+  if (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act)
+  {
+    mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
+    return false;
+  }
+
+  mhd_assert (mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
+  read_buf_reuse = false;
+  state_updated = false;
+  if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
+  {
+    // TODO: implement processing in pool memory if buffer is large enough
+    mhd_assert ((c->rq.cntn.recv_size + cntn_data_ready) <=
+                (uint_fast64_t) c->rq.cntn.lbuf.size);
+    memcpy (c->rq.cntn.lbuf.buf + c->rq.cntn.recv_size,
+            c->read_buffer, cntn_data_ready);
+    c->rq.cntn.recv_size += cntn_data_ready;
+    read_buf_reuse = true;
+    if (c->rq.cntn.recv_size == c->rq.cntn.cntn_size)
+    {
+      c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
+      state_updated = true;
+    }
+  }
+  else
+  {
+    const struct MHD_UploadAction *act;
+    mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
+
+    c->rq.cntn.recv_size += cntn_data_ready;
+    act = c->rq.app_act.head_act.data.upload.inc.cb (
+      c->rq.app_act.head_act.data.upload.inc.cls,
+      &(c->rq),
+      cntn_data_ready,
+      c->read_buffer);
+    c->rq.cntn.proc_size += cntn_data_ready;
+    read_buf_reuse = true;
+    state_updated = process_upload_action (c, act, false);
+  }
+
+  if (read_buf_reuse)
+  {
+    size_t data_left_size;
+    mhd_assert (c->read_buffer_offset >= cntn_data_ready);
+    data_left_size = c->read_buffer_offset - cntn_data_ready;
+    if (0 != data_left_size)
+      memmove (c->read_buffer, c->read_buffer + cntn_data_ready, 
data_left_size)
+      ;
+    c->read_buffer_offset = data_left_size;
+  }
+
+  return state_updated;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_process_request_body (struct MHD_Connection *restrict c)
+{
+  if (c->rq.have_chunked_upload)
+    return process_request_chunked_body (c);
+
+  return process_request_nonchunked_body (c);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c)
+{
+  const struct MHD_UploadAction *act;
+  mhd_assert (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act || \
+              mhd_ACTION_UPLOAD == c->rq.app_act.head_act.act);
+
+  if (mhd_ACTION_POST_PROCESS == c->rq.app_act.head_act.act)
+  {
+    mhd_assert (0 && "Not implemented yet"); // TODO: implement POST
+    return false;
+  }
+
+  if (NULL != c->rq.app_act.head_act.data.upload.full.cb)
+  {
+    mhd_assert (c->rq.cntn.recv_size == c->rq.cntn.cntn_size);
+    mhd_assert (0 == c->rq.cntn.proc_size);
+    mhd_assert (NULL != c->rq.cntn.lbuf.buf);
+    mhd_assert (c->rq.cntn.recv_size <= c->rq.cntn.lbuf.size);
+    // TODO: implement processing in pool memory if it is large enough
+    act = c->rq.app_act.head_act.data.upload.full.cb (
+      c->rq.app_act.head_act.data.upload.full.cls,
+      &(c->rq),
+      c->rq.cntn.recv_size,
+      c->rq.cntn.lbuf.buf);
+    c->rq.cntn.proc_size = c->rq.cntn.recv_size;
+  }
+  else
+  {
+    mhd_assert (NULL != c->rq.app_act.head_act.data.upload.inc.cb);
+    mhd_assert (c->rq.cntn.cntn_size == c->rq.cntn.proc_size);
+    act = c->rq.app_act.head_act.data.upload.inc.cb (
+      c->rq.app_act.head_act.data.upload.inc.cls,
+      &(c->rq),
+      0,
+      NULL);
+  }
+  return process_upload_action (c, act, true);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_stream_process_req_recv_finished (struct MHD_Connection *restrict c)
+{
+  if (NULL != c->rq.cntn.lbuf.buf)
+    mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf));
+  if (c->rq.cntn.cntn_size != c->rq.cntn.proc_size)
+    c->discard_request = true;
+  mhd_assert (NULL != c->rp.response);
+  c->state = MHD_CONNECTION_START_REPLY;
+  return true;
 }
diff --git a/src/mhd2/stream_process_request.h 
b/src/mhd2/stream_process_request.h
index e71a39b7..810fafd9 100644
--- a/src/mhd2/stream_process_request.h
+++ b/src/mhd2/stream_process_request.h
@@ -1,6 +1,7 @@
 /*
   This file is part of GNU libmicrohttpd
-  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+  Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
+  Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
 
   GNU libmicrohttpd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -23,17 +24,58 @@
  * @brief  The declarations of internal functions for requests parsing
  *         and processing
  * @author Karlson2k (Evgeny Grin)
+ *
+ * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
+ * contributors.
  */
 
 #ifndef MHD_STREAM_PROCESS_REQUEST_H
-#define MHD_STREAM_PROCESS_STATES_H 1
+#define MHD_STREAM_PROCESS_REQUEST_H 1
 
 #include "mhd_sys_options.h"
 
 #include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#include "mhd_str_types.h"
 
 struct MHD_Connection; /* forward declaration */
 
+/**
+ * Callback for iterating over GET parameters
+ * @param cls the iterator metadata
+ * @param name the name of the parameter
+ * @param value the value of the parameter
+ * @return bool to continue iterations,
+ *         false to stop the iteration
+ */
+typedef bool
+(MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3)
+ *mhd_GetArgumentInter)(void *restrict cls,
+                        const struct MHD_String *restrict name,
+                        const struct MHD_StringNullable *restrict value);
+
+/**
+ * Parse and unescape the arguments given by the client
+ * as part of the HTTP request URI.
+ *
+ * @param args_len the function to call on each key-value pair found
+ * @param[in,out] args argument URI string (after "?" in URI),
+ *        clobbered in the process!
+ * @param cb function to call on each key-value pair found
+ * @param cls the iterator context
+ * @param[out] enc_broken the pointer to get
+ * @return false on failure
+ *         true on success (parsing succeeded, @a cb always returned true)
+ */
+MHD_INTERNAL bool
+mhd_parse_get_args (size_t args_len,
+                    char *restrict args,
+                    mhd_GetArgumentInter cb,
+                    void *restrict cls)
+MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) MHD_FN_PAR_INOUT_ (2);
+
+
 /**
  * Find and parse the request line.
  * @param c the connection to process
@@ -42,7 +84,7 @@ struct MHD_Connection; /* forward declaration */
  *         false if not enough data yet in the receive buffer
  */
 MHD_INTERNAL bool
-mhd_get_request_line (struct MHD_Connection *restrict c)
+mhd_stream_get_request_line (struct MHD_Connection *restrict c)
 MHD_FN_PAR_NONNULL_ALL_;
 
 /**
@@ -50,11 +92,22 @@ MHD_FN_PAR_NONNULL_ALL_;
  * @param c the connection to process
  */
 MHD_INTERNAL void
-mhd_switch_to_rq_headers_processing (struct MHD_Connection *restrict c)
+mhd_stream_switch_to_rq_headers_proc (struct MHD_Connection *restrict c)
 MHD_FN_PAR_NONNULL_ALL_;
 
 /**
- * Find the end of the request headers and make basic header parsing.
+ * Reset request header processing state.
+ *
+ * This function resets the processing state before processing the header
+ * (or footer) line.
+ * @param c the connection to process
+ */
+MHD_INTERNAL void
+mhd_stream_reset_rq_hdr_proc_state (struct MHD_Connection *c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Find the end of the request GET parameters.
  * Advance to the next state when done, handle errors.
  * @param c the connection to process
  * @param process_footers if true then footers are processed,
@@ -64,18 +117,68 @@ MHD_FN_PAR_NONNULL_ALL_;
  *         false if not enough data yet in the receive buffer
  */
 MHD_INTERNAL bool
-mhd_get_req_headers (struct MHD_Connection *restrict c, bool process_footers)
+mhd_stream_get_request_headers (struct MHD_Connection *restrict c,
+                                bool process_footers)
 MHD_FN_PAR_NONNULL_ALL_;
 
 /**
- * Parse the various headers; figure out the size
- * of the upload and make sure the headers follow
- * the protocol.  Advance to the appropriate state.
+ * Parse the various request headers; figure out the size of the upload and
+ * make sure the headers follow the protocol.
+ * Advance to the appropriate state.
  *
  * @param c the connection to process
  */
 MHD_INTERNAL void
-mhd_parse_connection_headers (struct MHD_Connection *restrict c)
+mhd_stream_parse_connection_headers (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Call application request handling callback, process action given by app.
+ * Advance to the next state when done, handle errors.
+ * @param c the connection to process
+ * @return true if advanced to the next state and the next state could
+ *              be processes right now,
+ *         false if connection is suspended or aborted or more data needed
+ *         to process the next state
+ */
+MHD_INTERNAL bool
+mhd_stream_call_app_request_cb (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Process non-chunked request body or upload chunking encoding.
+ * Call the upload handler of the application.
+ * Advance to the next state when done, handle errors.
+ *
+ * @param c the connection to process
+ * @return true if advanced to the next state,
+ *         false if more data needed or connection is suspended or aborted
+ */
+MHD_INTERNAL bool
+mhd_stream_process_request_body (struct MHD_Connection *restrict c)
 MHD_FN_PAR_NONNULL_ALL_;
 
-#endif /* ! MHD_STREAM_PROCESS_STATES_H */
+/**
+ * Call application final upload callback, process action given by app.
+ * Advance to the next state, handle errors.
+ * @param c the connection to process
+ * @return true if advanced to the next state,
+ *         false if connection is suspended or aborted
+ */
+MHD_INTERNAL bool
+mhd_stream_call_app_final_upload_cb (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Process finalisation of request receiving.
+ * Advance to the next state, handle errors.
+ * @param c the connection to process
+ * @return true if advanced to the next state,
+ *         false if connection is suspended or aborted
+ */
+MHD_INTERNAL bool
+mhd_stream_process_req_recv_finished (struct MHD_Connection *restrict c)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+#endif /* ! MHD_STREAM_PROCESS_REQUEST_H */
diff --git a/src/mhd2/stream_process_states.c b/src/mhd2/stream_process_states.c
index 32b3d22e..d933490f 100644
--- a/src/mhd2/stream_process_states.c
+++ b/src/mhd2/stream_process_states.c
@@ -1,6 +1,7 @@
 /*
   This file is part of GNU libmicrohttpd
-  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+  Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
+  Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
 
   GNU libmicrohttpd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -23,13 +24,20 @@
  * @brief  The definitions of internal functions for processing
  *         stream states
  * @author Karlson2k (Evgeny Grin)
+ *
+ * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
+ * contributors.
  */
 
 #include "mhd_sys_options.h"
 #include "sys_bool_type.h"
 
+#include "mhd_str_macros.h"
+
 #include "mhd_connection.h"
 #include "stream_process_states.h"
+#include "stream_funcs.h"
+#include "stream_process_request.h"
 
 
 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
@@ -37,19 +45,24 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
 {
   struct MHD_Daemon *const restrict d = c->daemon;
 
-  enum MHD_Result ret;
-
   /* 'daemon' is not used if epoll is not available and asserts are disabled */
   (void) d; /* Mute compiler warning */
 
+  mhd_assert (c->resuming || ! c->suspended);
+  if (c->resuming)
+  {
+    // TODO: finish resuming, update activity mark
+    // TODO: move to special function
+  }
+
   if ((mhd_SOCKET_ERR_NO_ERROR != c->sk_discnt_err) ||
       (0 != (c->sk_ready & mhd_SOCKET_NET_STATE_ERROR_READY)))
   {
     mhd_assert ((mhd_SOCKET_ERR_NO_ERROR != c->sk_discnt_err) || \
-                mhd_SOCKET_ERR_IS_HARD(c->sk_discnt_err));
+                mhd_SOCKET_ERR_IS_HARD (c->sk_discnt_err));
     if ((mhd_SOCKET_ERR_NO_ERROR == c->sk_discnt_err) ||
         (mhd_SOCKET_ERR_NOT_CHECKED == c->sk_discnt_err))
-      c->sk_discnt_err = mhd_socket_error_get_from_socket(c->socket_fd);
+      c->sk_discnt_err = mhd_socket_error_get_from_socket (c->socket_fd);
     mhd_conn_pre_close_skt_err (c);
     return false;
   }
@@ -63,21 +76,21 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
     {
     case MHD_CONNECTION_INIT:
     case MHD_CONNECTION_REQ_LINE_RECEIVING:
-      if (mhd_get_request_line (c))
+      if (mhd_stream_get_request_line (c))
       {
         mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING < c->state);
-        mhd_assert ((MHD_IS_HTTP_VER_SUPPORTED (c->rq.http_ver)) \
+        mhd_assert ((MHD_HTTP_VERSION_IS_SUPPORTED (c->rq.http_ver)) \
                     || (c->discard_request));
         continue;
       }
       mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING >= c->state);
       break;
     case MHD_CONNECTION_REQ_LINE_RECEIVED:
-      mhd_switch_to_rq_headers_processing (c);
+      mhd_stream_switch_to_rq_headers_proc (c);
       mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVED != c->state);
       continue;
     case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
-      if (mhd_get_req_headers (c, false))
+      if (mhd_stream_get_request_headers (c, false))
       {
         mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING < c->state);
         mhd_assert ((MHD_CONNECTION_HEADERS_RECEIVED == c->state) || \
@@ -87,91 +100,49 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
       mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING == c->state);
       break;
     case MHD_CONNECTION_HEADERS_RECEIVED:
-      mhd_parse_connection_headers (c);
-      if (MHD_CONNECTION_HEADERS_RECEIVED != c->state)
-        continue;
-      c->state = MHD_CONNECTION_HEADERS_PROCESSED;
-      if (c->suspended)
-        break;
+      mhd_stream_parse_connection_headers (c);
+      mhd_assert (c->state != MHD_CONNECTION_HEADERS_RECEIVED);
       continue;
     case MHD_CONNECTION_HEADERS_PROCESSED:
-      call_connection_handler (c);
-      if (MHD_CONNECTION_HEADERS_PROCESSED != c->state)
-        continue;
-      if (c->suspended)
-        continue;
-
-      if ( (NULL == c->rp.response) &&
-           (need_100_continue (c)) &&
-           /* If the client is already sending the payload (body)
-              there is no need to send "100 Continue" */
-           (0 == c->read_buffer_offset) )
-      {
-        c->state = MHD_CONNECTION_CONTINUE_SENDING;
-        break;
-      }
-      if ( (NULL != c->rp.response) &&
-           (0 != c->rq.remaining_upload_size) )
+      if (mhd_stream_call_app_request_cb (c))
       {
-        /* we refused (no upload allowed!) */
-        c->rq.remaining_upload_size = 0;
-        /* force close, in case client still tries to upload... */
-        c->discard_request = true;
+        mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED < c->state);
+        continue;
       }
-      c->state = (0 == c->rq.remaining_upload_size)
-                          ? MHD_CONNECTION_FULL_REQ_RECEIVED
-                          : MHD_CONNECTION_BODY_RECEIVING;
-      if (c->suspended)
-        break;
-      continue;
+      // TODO: add assert
+      break;
     case MHD_CONNECTION_CONTINUE_SENDING:
       if (c->continue_message_write_offset ==
-          mhd_SSTR_LEN (HTTP_100_CONTINUE))
+          mhd_SSTR_LEN (mdh_HTTP_1_1_100_CONTINUE_REPLY))
       {
         c->state = MHD_CONNECTION_BODY_RECEIVING;
         continue;
       }
       break;
     case MHD_CONNECTION_BODY_RECEIVING:
-      mhd_assert (0 != c->rq.remaining_upload_size);
+      mhd_assert (c->rq.cntn.recv_size < c->rq.cntn.cntn_size);
       mhd_assert (! c->discard_request);
       mhd_assert (NULL == c->rp.response);
-      if (0 != c->read_buffer_offset)
-      {
-        process_request_body (c);           /* loop call */
-        if (MHD_CONNECTION_BODY_RECEIVING != c->state)
-          continue;
-      }
-      /* Modify here when queueing of the response during data processing
-         will be supported */
+      if (0 == c->read_buffer_offset)
+        break; /* Need more data to process */
+
+      if (mhd_stream_process_request_body (c))
+        continue;
       mhd_assert (! c->discard_request);
       mhd_assert (NULL == c->rp.response);
-      if (0 == c->rq.remaining_upload_size)
-      {
-        c->state = MHD_CONNECTION_BODY_RECEIVED;
-        continue;
-      }
       break;
     case MHD_CONNECTION_BODY_RECEIVED:
       mhd_assert (! c->discard_request);
       mhd_assert (NULL == c->rp.response);
-      if (0 == c->rq.remaining_upload_size)
-      {
-        if (c->rq.have_chunked_upload)
-        {
-          /* Reset counter variables reused for footers */
-          c->rq.num_cr_sp_replaced = 0;
-          c->rq.skipped_broken_lines = 0;
-          reset_rq_header_processing_state (c);
-          c->state = MHD_CONNECTION_FOOTERS_RECEIVING;
-        }
-        else
-          c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
-        continue;
-      }
-      break;
+      mhd_assert (c->rq.have_chunked_upload);
+      /* Reset counter variables reused for footers */
+      c->rq.num_cr_sp_replaced = 0;
+      c->rq.skipped_broken_lines = 0;
+      mhd_stream_reset_rq_hdr_proc_state (c);
+      c->state = MHD_CONNECTION_FOOTERS_RECEIVING;
+      continue;
     case MHD_CONNECTION_FOOTERS_RECEIVING:
-      if (get_req_headers (c, true))
+      if (mhd_stream_get_request_headers (c, true))
       {
         mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING < c->state);
         mhd_assert ((MHD_CONNECTION_FOOTERS_RECEIVED == c->state) || \
@@ -181,22 +152,22 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
       mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING == c->state);
       break;
     case MHD_CONNECTION_FOOTERS_RECEIVED:
-      /* The header, the body, and the footers of the request has been 
received,
-       * switch to the final processing of the request. */
       c->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
       continue;
     case MHD_CONNECTION_FULL_REQ_RECEIVED:
-      call_connection_handler (c);     /* "final" call */
-      if (c->state != MHD_CONNECTION_FULL_REQ_RECEIVED)
+      if (mhd_stream_call_app_final_upload_cb (c))
+      {
+        mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING != c->state);
         continue;
-      if (NULL == c->rp.response)
-        break;                  /* try again next time */
-      /* Response is ready, start reply */
-      c->state = MHD_CONNECTION_START_REPLY;
-      continue;
+      }
+      break;
+    case MHD_CONNECTION_REQ_RECV_FINISHED:
+      if (mhd_stream_process_req_recv_finished (c))
+        continue;
+      break;
     case MHD_CONNECTION_START_REPLY:
       mhd_assert (NULL != c->rp.response);
-      connection_switch_from_recv_to_send (c);
+      mhd_stream_switch_from_recv_to_send (c);
       if (MHD_NO == build_header_response (c))
       {
         /* oops - close! */
@@ -213,7 +184,7 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
       break;
     case MHD_CONNECTION_HEADERS_SENT:
       mhd_assert (0 && "Not implemented yet");
-#if 0 //def UPGRADE_SUPPORT // TODO: upgrade support
+#if 0 // def UPGRADE_SUPPORT // TODO: upgrade support
       if (NULL != c->rp.response->upgrade_handler)
       {
         c->state = MHD_CONNECTION_UPGRADE;
@@ -296,7 +267,7 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
         if (MHD_NO != try_ready_chunked_body (c, &finished))
         {
           c->state = finished ? MHD_CONNECTION_CHUNKED_BODY_SENT :
-                              MHD_CONNECTION_CHUNKED_BODY_READY;
+                     MHD_CONNECTION_CHUNKED_BODY_READY;
           continue;
         }
         /* mutex was already unlocked by try_ready_chunked_body */
@@ -346,7 +317,13 @@ mhd_conn_process_data (struct MHD_Connection *restrict c)
     }
     break;
   }
-  if (connection_check_timedout (c))
+
+  if (c->suspended)
+  {
+    // TODO: process
+  }
+
+  if (connection_check_timedout (c)) // TODO: centralise timeout checks
   {
     MHD_connection_close_ (c,
                            MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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