gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (8dc93b08 -> f02888d4)


From: gnunet
Subject: [libmicrohttpd] branch master updated (8dc93b08 -> f02888d4)
Date: Tue, 20 Jun 2023 22:24:13 +0200

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 8dc93b08 base64 decoding: added more compact code version
     new eaa3be77 Refactoring: check whether memory block is resizable
     new bd605be2 Re-implemented parsing of the request line from scratch.
     new b483c0f6 microhttpd.h: fixed typos in comments
     new 9141692a Renamed connection state for clarity
     new 69da8569 Request body processing: removed impossible code paths
     new eaf1fa08 Re-implemented parsing of the request headers and footers 
from scratch.
     new 4e8e5e65 Removed request line and headers processing old functions and 
variables
     new dce20846 tests: minor improvemnts
     new 4b8fb070 daemon: added debug member to avoid accept4() usage
     new 87d40361 testzzuf: added special debug functions
     new 40b67551 testzzuf: re-worked zzuf testing
     new c0f7cbb2 Added back testing with socat as a fallback option
     new 6878cd91 Added new tests with header fold
     new 04ad057a Added test with folded header placed last
     new 48ae1a36 Added test with large folded header
     new edde133d Added tests with single and double folded header
     new 127a964c connection.c: corrected error responses
     new 2e996ee5 Added proper connection's buffers pre-initialisaion
     new 5a9f64bc connection: fixed pipelined requests processing
     new c1b6751c Added checks for correct values specified for connection 
memory limits
     new 30bf0556 process_request_body(): minor readability improvementы
     new f7bae2ce Minor refactoring for partially processed request body
     new a80d8060 Adjusted buffer increase default step size
     new 67061d5c process new connection: fixed missing mutex unlock in error 
handling path
     new 0f20fe46 Fixed possible timeout value trim on 32-bits platforms
     new e620738a W32 VS Projects: fixed code parsing
     new 8fd9b6bd Fixed some comments
     new 8b17c915 try_grow_read_buffer(): better handling of edge cases
     new f02888d4 Focused all read-buffer grows in a single point, related 
improvements.

The 29 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 configure.ac                                       |  103 +-
 src/include/microhttpd.h                           |    8 +-
 src/lib/internal.c                                 |   10 +-
 src/microhttpd/connection.c                        | 2997 +++++++++++++++-----
 src/microhttpd/connection.h                        |    8 +
 src/microhttpd/daemon.c                            |   79 +-
 src/microhttpd/internal.c                          |   12 +-
 src/microhttpd/internal.h                          |  185 +-
 src/microhttpd/memorypool.c                        |   32 +
 src/microhttpd/memorypool.h                        |   14 +
 src/microhttpd/test_auth_parse.c                   |   13 +-
 src/microhttpd/test_mhd_version.c                  |   25 +-
 src/testcurl/Makefile.am                           |   31 +
 src/testcurl/test_long_header.c                    |    2 +
 .../{test_head.c => test_put_header_fold.c}        |  810 ++++--
 src/testzzuf/Makefile.am                           |  143 +-
 src/testzzuf/mhd_debug_funcs.c                     |  108 +
 src/testzzuf/mhd_debug_funcs.h                     |   57 +
 src/testzzuf/socat.c                               |  117 -
 src/testzzuf/test_get.c                            | 1749 ++++++++++--
 src/testzzuf/test_get_chunked.c                    |  364 ---
 src/testzzuf/test_long_header.c                    |  265 --
 src/testzzuf/test_post.c                           |  416 ---
 src/testzzuf/test_post_form.c                      |  432 ---
 src/testzzuf/test_put.c                            |  380 ---
 src/testzzuf/test_put_chunked.c                    |  395 ---
 src/testzzuf/test_put_large.c                      |  403 ---
 src/testzzuf/zzuf_socat_test_runner.sh             |  118 +
 src/testzzuf/zzuf_test_runner.sh                   |   94 +
 w32/common/cpp.hint                                |    3 +
 w32/common/libmicrohttpd-files.vcxproj             |    3 +
 w32/common/libmicrohttpd-filters.vcxproj           |    3 +
 32 files changed, 5263 insertions(+), 4116 deletions(-)
 copy src/testcurl/{test_head.c => test_put_header_fold.c} (54%)
 create mode 100644 src/testzzuf/mhd_debug_funcs.c
 create mode 100644 src/testzzuf/mhd_debug_funcs.h
 delete mode 100644 src/testzzuf/socat.c
 delete mode 100644 src/testzzuf/test_get_chunked.c
 delete mode 100644 src/testzzuf/test_long_header.c
 delete mode 100644 src/testzzuf/test_post.c
 delete mode 100644 src/testzzuf/test_post_form.c
 delete mode 100644 src/testzzuf/test_put.c
 delete mode 100644 src/testzzuf/test_put_chunked.c
 delete mode 100644 src/testzzuf/test_put_large.c
 create mode 100755 src/testzzuf/zzuf_socat_test_runner.sh
 create mode 100755 src/testzzuf/zzuf_test_runner.sh
 create mode 100644 w32/common/cpp.hint

diff --git a/configure.ac b/configure.ac
index c329812c..8b7489c3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1789,6 +1789,7 @@ AS_VAR_IF([use_heavy_tests], ["yes"],
   ]
 )
 AM_CONDITIONAL([HEAVY_TESTS],[test "x$use_heavy_tests" = "xyes"])
+AM_CONDITIONAL([VHEAVY_TESTS],[test "x$use_vheavy_tests" = "xyes"])
 AM_CONDITIONAL([TESTS_STRESS_OS],[false])
 
 AC_ARG_ENABLE([[poll]],
@@ -3052,47 +3053,6 @@ AS_IF([[test "x$enable_postprocessor" != "xno"]],
 AM_CONDITIONAL([HAVE_POSTPROCESSOR], [test "x$enable_postprocessor" != "xno"])
 AC_MSG_RESULT([[$enable_postprocessor]])
 
-
-# optional: have zzuf, socat?
-run_zzuf_tests="no"
-AS_VAR_IF([use_heavy_tests],["yes"],
-  [
-    AS_VAR_IF([enable_curl],["yes"],
-      [
-        AC_CHECK_PROG([have_zzuf],[zzuf],[yes],[no])
-        AS_VAR_IF([have_zzuf],["yes"],
-          [
-            AC_CHECK_PROG([have_socat],[socat],[yes],[no])
-            AS_VAR_IF([have_socat],["yes"],
-              [
-                run_zzuf_tests="yes"
-                run_zzuf_tests_MSG="yes"
-              ],
-              [
-                run_zzuf_tests="no"
-                run_zzuf_tests_MSG="no, socat tool not found"
-              ]
-            )
-          ],
-          [
-            run_zzuf_tests="no"
-            run_zzuf_tests_MSG="no, zzuf tool not found"
-          ]
-        )
-      ],
-      [
-        run_zzuf_tests="no"
-        run_zzuf_tests_MSG="no, tests with libcurl are not enabled"
-      ]
-    )
-  ],
-  [
-    run_zzuf_tests="no"
-    run_zzuf_tests_MSG="no, heavy tests are not enabled"
-  ]
-)
-AM_CONDITIONAL([RUN_ZZUF_TESTS],[test "x$run_zzuf_tests" = "xyes"])
-
 have_gnutls=no
 have_gnutls_sni=no
 have_gcrypt=no
@@ -4883,6 +4843,65 @@ int main(void)
  ]
 )
 
+# fuzzing tests
+run_zzuf_tests="no"
+zzuf_socat_mandatory="no"
+AS_VAR_IF([use_heavy_tests],["yes"],
+  [
+    AS_VAR_IF([enable_curl],["yes"],
+      [
+        AC_PATH_PROG([ZZUF],[zzuf],[no])
+        AS_VAR_IF([ZZUF],["no"],
+          [
+            run_zzuf_tests="no"
+            run_zzuf_tests_MSG="no, zzuf tool not found"
+          ],
+          [
+               AC_PATH_PROG([SOCAT],[socat],[no])
+            AS_IF([test "x${ac_cv_func_accept4}" = "xyes" && test 
"x${enable_asserts}" = "xno"],
+              [
+                zzuf_socat_mandatory="yes"
+                       AS_VAR_IF([SOCAT],["no"],
+                  [run_zzuf_tests_MSG="no, socat not found, but required for 
fuzzing tests on this platform without asserts enabled"],
+                  [
+                           run_zzuf_tests="yes"
+                           run_zzuf_tests_MSG="yes, with zzuf and socat tools"
+                  ]
+                )
+              ],
+              [test -n "${enabled_sanitizers}"],
+              [
+                zzuf_socat_mandatory="yes"
+                       AS_VAR_IF([SOCAT],["no"],
+                  [run_zzuf_tests_MSG="no, socat not found, but required for 
fuzzing tests when sanitizers enabled"],
+                  [
+                           run_zzuf_tests="yes"
+                           run_zzuf_tests_MSG="yes, with zzuf and socat tools"
+                  ]
+                )
+              ],
+              [
+                run_zzuf_tests="yes"
+                run_zzuf_tests_MSG="yes, with zzuf tool"
+              ]
+            )
+          ]
+        )
+      ],
+      [
+        run_zzuf_tests="no"
+        run_zzuf_tests_MSG="no, tests with libcurl are not enabled"
+      ]
+    )
+  ],
+  [
+    run_zzuf_tests="no"
+    run_zzuf_tests_MSG="no, heavy tests are not enabled"
+  ]
+)
+AM_CONDITIONAL([RUN_ZZUF_TESTS],[test "x$run_zzuf_tests" = "xyes"])
+AM_CONDITIONAL([FORCE_USE_ZZUF_SOCAT],[test "x$zzuf_socat_mandatory" = "xyes"])
+
 # Final flags that may interfere with autoconf detections
 AS_CASE([${enable_build_type}],[debug|debugger],
   [ # Debug build or build for walking with debugger
@@ -4955,6 +4974,8 @@ AC_CONFIG_COMMANDS([po-directories],
 # not contain the actual installation.
 AC_DEFINE_DIR([MHD_PLUGIN_INSTALL_PREFIX], [libdir/libmicrohttpd], [tls 
plugins])
 
+AC_SUBST([ZZUF])
+AC_SUBST([SOCAT])
 
 # should experimental code be compiled (code that may not yet compile)?
 AC_MSG_CHECKING(whether to compile experimental code)
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 3db5378d..8745367c 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
  * they are parsed as decimal numbers.
  * Example: 0x01093001 = 1.9.30-1.
  */
-#define MHD_VERSION 0x00097701
+#define MHD_VERSION 0x00097703
 
 /* If generic headers don't work on your platform, include headers
    which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -1626,6 +1626,7 @@ enum MHD_OPTION
    * Values above 128k are unlikely to result in much benefit, as half
    * of the memory will be typically used for IO, and TCP buffers are
    * unlikely to support window sizes above 64k on most systems.
+   * Values below 64 bytes are completely unusable.
    */
   MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1,
 
@@ -1864,7 +1865,8 @@ enum MHD_OPTION
 
   /**
    * Increment to use for growing the read buffer (followed by a
-   * `size_t`). Must fit within #MHD_OPTION_CONNECTION_MEMORY_LIMIT.
+   * `size_t`).
+   * Must not be higher than 1/4 of #MHD_OPTION_CONNECTION_MEMORY_LIMIT.
    */
   MHD_OPTION_CONNECTION_MEMORY_INCREMENT = 21,
 
@@ -6200,7 +6202,7 @@ enum MHD_FEATURE
   /**
    * Get whether the SHA-256-based hashing algorithms are supported for Digest
    * Authorization.
-   * It it always supported since #MHD_VERSION 0x00096200 if Digest Auth
+   * It is always supported since #MHD_VERSION 0x00096200 if Digest Auth
    * module is built unless manually disabled in a custom build.
    * @note Available since #MHD_VERSION 0x00097701
    */
diff --git a/src/lib/internal.c b/src/lib/internal.c
index ade15e0a..a8af21ea 100644
--- a/src/lib/internal.c
+++ b/src/lib/internal.c
@@ -38,10 +38,10 @@ MHD_state_to_string (enum MHD_CONNECTION_STATE state)
   {
   case MHD_CONNECTION_INIT:
     return "connection init";
-  case MHD_CONNECTION_URL_RECEIVED:
+  case MHD_CONNECTION_REQ_LINE_RECEIVED:
     return "connection url received";
-  case MHD_CONNECTION_HEADER_PART_RECEIVED:
-    return "header partially received";
+  case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
+    return "header receiving";
   case MHD_CONNECTION_HEADERS_RECEIVED:
     return "headers received";
   case MHD_CONNECTION_HEADERS_PROCESSED:
@@ -52,8 +52,8 @@ MHD_state_to_string (enum MHD_CONNECTION_STATE state)
     return "continue sent";
   case MHD_CONNECTION_BODY_RECEIVED:
     return "body received";
-  case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-    return "footer partially received";
+  case MHD_CONNECTION_FOOTERS_RECEIVING:
+    return "footers receiving";
   case MHD_CONNECTION_FOOTERS_RECEIVED:
     return "footers received";
   case MHD_CONNECTION_HEADERS_SENDING:
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 859ca820..4d912ce8 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -56,6 +56,16 @@
 #include "mhd_send.h"
 #include "mhd_assert.h"
 
+/**
+ * The reasonable length of the upload chunk "header" (the size specifier
+ * with optional chunk extension).
+ * MHD tries to keep the space in the read buffer large enough to read
+ * the chunk "header" in one step.
+ * The real "header" could be much larger, it will be handled correctly
+ * anyway, however it may require several rounds of buffer grow.
+ */
+#define MHD_CHUNK_HEADER_REASONABLE_LEN 24
+
 /**
  * Message to transmit when http 1.1 request is received
  */
@@ -64,17 +74,269 @@
 /**
  * Response text used when the request (http header) is too big to
  * be processed.
- *
- * Intentionally empty here to keep our memory footprint
- * minimal.
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_TOO_BIG \
-  "<html><head><title>Request too big</title></head><body>Your HTTP header was 
too big for the memory constraints of this webserver.</body></html>"
+  "<html>" \
+  "<head><title>Request too big</title></head>" \
+  "<body>Request HTTP header is too big for the memory constraints " \
+  "of this webserver.</body>" \
+  "</html>"
 #else
 #define REQUEST_TOO_BIG ""
 #endif
 
+/**
+ * Response text used when the request line has more then two whitespaces.
+ */
+#ifdef HAVE_MESSAGES
+#define RQ_LINE_TOO_MANY_WSP \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>The request line has more then two whitespaces.</body>" \
+  "</html>"
+#else
+#define RQ_LINE_TOO_MANY_WSP ""
+#endif
+
+/**
+ * Response text used when the request HTTP header has bare CR character
+ * without LF character (and CR is not allowed to be treated as whitespace).
+ */
+#ifdef HAVE_MESSAGES
+#define BARE_CR_IN_HEADER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>Request HTTP header has bare CR character without " \
+  "following LF character.</body>" \
+  "</html>"
+#else
+#define BARE_CR_IN_HEADER ""
+#endif
+
+/**
+ * Response text used when the request HTTP footer has bare CR character
+ * without LF character (and CR is not allowed to be treated as whitespace).
+ */
+#ifdef HAVE_MESSAGES
+#define BARE_CR_IN_FOOTER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>Request HTTP footer has bare CR character without " \
+  "following LF character.</body>" \
+  "</html>"
+#else
+#define BARE_CR_IN_FOOTER ""
+#endif
+
+/**
+ * Response text used when the request HTTP header has bare LF character
+ * without CR character.
+ */
+#ifdef HAVE_MESSAGES
+#define BARE_LF_IN_HEADER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>Request HTTP header has bare LF character without " \
+  "preceding CR character.</body>" \
+  "</html>"
+#else
+#define BARE_LF_IN_HEADER ""
+#endif
+
+/**
+ * Response text used when the request HTTP footer has bare LF character
+ * without CR character.
+ */
+#ifdef HAVE_MESSAGES
+#define BARE_LF_IN_FOOTER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>Request HTTP footer has bare LF character without " \
+  "preceding CR character.</body>" \
+  "</html>"
+#else
+#define BARE_LF_IN_FOOTER ""
+#endif
+
+/**
+ * Response text used when the request line has invalid characters in URI.
+ */
+#ifdef HAVE_MESSAGES
+#define RQ_TARGET_INVALID_CHAR \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request has invalid characters in " \
+  "the request-target.</body>" \
+  "</html>"
+#else
+#define RQ_TARGET_INVALID_CHAR ""
+#endif
+
+/**
+ * Response text used when line folding is used in request headers.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_OBS_FOLD \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>Obsolete line folding is used in HTTP request header.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_OBS_FOLD ""
+#endif
+
+/**
+ * Response text used when line folding is used in request footers.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_OBS_FOLD_FOOTER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>Obsolete line folding is used in HTTP request footer.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_OBS_FOLD_FOOTER ""
+#endif
+
+/**
+ * Response text used when the request has whitespace at the start
+ * of the first header line.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_WSP_BEFORE_HEADER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request has whitespace between the request line and " \
+  "the first header.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_WSP_BEFORE_HEADER ""
+#endif
+
+/**
+ * Response text used when the request has whitespace at the start
+ * of the first footer line.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_WSP_BEFORE_FOOTER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>First HTTP footer line has whitespace at the first " \
+  "position.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_WSP_BEFORE_FOOTER ""
+#endif
+
+/**
+ * Response text used when the whitespace found before colon (inside header
+ * name or between header name and colon).
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_WSP_IN_HEADER_NAME \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request has whitespace before the first colon " \
+  "in header line.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_WSP_IN_HEADER_NAME ""
+#endif
+
+/**
+ * Response text used when the whitespace found before colon (inside header
+ * name or between header name and colon).
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_WSP_IN_FOOTER_NAME \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request has whitespace before the first colon " \
+  "in footer line.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_WSP_IN_FOOTER_NAME ""
+#endif
+
+/**
+ * Response text used when request header has invalid character.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_INVALID_CHR_IN_HEADER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request has invalid character in header.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_INVALID_CHR_IN_HEADER ""
+#endif
+
+/**
+ * Response text used when request header has invalid character.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_INVALID_CHR_IN_FOOTER \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request has invalid character in footer.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_INVALID_CHR_IN_HEADER ""
+#endif
+
+/**
+ * Response text used when request header has no colon character.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_HEADER_WITHOUT_COLON \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request header line has no colon character.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_INVALID_CHR_IN_HEADER ""
+#endif
+
+/**
+ * Response text used when request footer has no colon character.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_FOOTER_WITHOUT_COLON \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request footer line has no colon character.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_FOOTER_WITHOUT_COLON ""
+#endif
+
+/**
+ * Response text used when request header has zero-length header (filed) name.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_EMPTY_HEADER_NAME \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request header has empty header name.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_EMPTY_HEADER_NAME ""
+#endif
+
+/**
+ * Response text used when request header has zero-length header (filed) name.
+ */
+#ifdef HAVE_MESSAGES
+#define ERR_RSP_EMPTY_FOOTER_NAME \
+  "<html>" \
+  "<head><title>Request broken</title></head>" \
+  "<body>HTTP request footer has empty footer name.</body>" \
+  "</html>"
+#else
+#define ERR_RSP_EMPTY_FOOTER_NAME ""
+#endif
+
 /**
  * Response text used when the request (http header) does not
  * contain a "Host:" header and still claims to be HTTP 1.1.
@@ -84,13 +346,17 @@
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_LACKS_HOST \
-  "<html><head><title>&quot;Host:&quot; header required</title></head><body>In 
HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 
request lacked such a header.</body></html>"
+  "<html>" \
+  "<head><title>&quot;Host:&quot; header required</title></head>" \
+  "<body>HTTP/1.1 request without <b>&quot;Host:&quot;</b>.</body>"\
+  "</html>"
+
 #else
 #define REQUEST_LACKS_HOST ""
 #endif
 
 /**
- * Response text used when the request has unsupported "Transfer-Enconding:".
+ * Response text used when the request has unsupported "Transfer-Encoding:".
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_UNSUPPORTED_TR_ENCODING \
@@ -104,7 +370,7 @@
 
 /**
  * Response text used when the request has unsupported both headers:
- * "Transfer-Enconding:" and "Content-Length:"
+ * "Transfer-Encoding:" and "Content-Length:"
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_LENGTH_WITH_TR_ENCODING \
@@ -126,7 +392,8 @@
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_MALFORMED \
-  "<html><head><title>Request malformed</title></head><body>Your HTTP request 
was syntactically incorrect.</body></html>"
+  "<html><head><title>Request malformed</title></head>" \
+  "<body>HTTP request is syntactically incorrect.</body></html>"
 #else
 #define REQUEST_MALFORMED ""
 #endif
@@ -137,7 +404,8 @@
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_CHUNKED_MALFORMED \
-  "<html><head><title>Request malformed</title></head><body>Your HTTP chunked 
encoding was syntactically incorrect.</body></html>"
+  "<html><head><title>Request malformed</title></head>" \
+  "<body>HTTP chunked encoding is syntactically incorrect.</body></html>"
 #else
 #define REQUEST_CHUNKED_MALFORMED ""
 #endif
@@ -147,7 +415,9 @@
  */
 #ifdef HAVE_MESSAGES
 #define REQUEST_CHUNK_TOO_LARGE \
-  "<html><head><title>Request content too large</title></head><body>The chunk 
size used in your HTTP chunked encoded request is too large.</body></html>"
+  "<html><head><title>Request content too large</title></head>" \
+  "<body>The chunk size used in HTTP chunked encoded " \
+  "request is too large.</body></html>"
 #else
 #define REQUEST_CHUNK_TOO_LARGE ""
 #endif
@@ -158,7 +428,8 @@
 #ifdef HAVE_MESSAGES
 #define REQUEST_CONTENTLENGTH_TOOLARGE \
   "<html><head><title>Request content too large</title></head>" \
-  "<body>Your HTTP request has too large value for <b>Content-Length</b> 
header.</body></html>"
+  "<body>HTTP request has too large value for " \
+  "<b>Content-Length</b> header.</body></html>"
 #else
 #define REQUEST_CONTENTLENGTH_TOOLARGE ""
 #endif
@@ -170,7 +441,8 @@
 #ifdef HAVE_MESSAGES
 #define REQUEST_CONTENTLENGTH_MALFORMED \
   "<html><head><title>Request malformed</title></head>" \
-  "<body>Your HTTP request has wrong value for <b>Content-Length</b> 
header.</body></html>"
+  "<body>HTTP request has wrong value for " \
+  "<b>Content-Length</b> header.</body></html>"
 #else
 #define REQUEST_CONTENTLENGTH_MALFORMED ""
 #endif
@@ -182,10 +454,13 @@
  * minimal.
  */
 #ifdef HAVE_MESSAGES
-#define INTERNAL_ERROR \
-  "<html><head><title>Internal server error</title></head><body>Please ask the 
developer of this Web server to carefully read the GNU libmicrohttpd 
documentation about connection management and blocking.</body></html>"
+#define ERROR_MSG_DATA_NOT_HANDLED_BY_APP \
+  "<html><head><title>Internal server error</title></head>" \
+  "<body>Please ask the developer of this Web server to carefully " \
+  "read the GNU libmicrohttpd documentation about connection "\
+  "management and blocking.</body></html>"
 #else
-#define INTERNAL_ERROR ""
+#define ERROR_MSG_DATA_NOT_HANDLED_BY_APP ""
 #endif
 
 /**
@@ -193,7 +468,9 @@
  */
 #ifdef HAVE_MESSAGES
 #define REQ_HTTP_VER_IS_TOO_OLD \
-  "<html><head><title>Requested HTTP version is not 
supported</title></head><body>Requested HTTP version is too old and not 
supported.</body></html>"
+  "<html><head><title>Requested HTTP version is not supported</title></head>" \
+  "<body>Requested HTTP version is too old and not " \
+  "supported.</body></html>"
 #else
 #define REQ_HTTP_VER_IS_TOO_OLD ""
 #endif
@@ -203,7 +480,8 @@
  */
 #ifdef HAVE_MESSAGES
 #define REQ_HTTP_VER_IS_NOT_SUPPORTED \
-  "<html><head><title>Requested HTTP version is not 
supported</title></head><body>Requested HTTP version is not 
supported.</body></html>"
+  "<html><head><title>Requested HTTP version is not supported</title></head>" \
+  "<body>Requested HTTP version is not supported.</body></html>"
 #else
 #define REQ_HTTP_VER_IS_NOT_SUPPORTED ""
 #endif
@@ -276,57 +554,59 @@ MHD_connection_alloc_memory_ (struct MHD_Connection 
*connection,
 {
   struct MHD_Connection *const c = connection; /* a short alias */
   struct MemoryPool *const pool = c->pool;     /* a short alias */
-  size_t need_to_free; /**< The required amount of free memory */
+  size_t need_to_be_freed; /**< The required amount of additional free memory 
*/
   void *res;
 
-  res = MHD_pool_try_alloc (pool, size, &need_to_free);
-  if (NULL == res)
+  res = MHD_pool_try_alloc (pool, size, &need_to_be_freed);
+  if (NULL != res)
+    return res;
+
+  if (MHD_pool_is_resizable_inplace (pool,
+                                     c->write_buffer,
+                                     c->write_buffer_size))
   {
-    if (NULL != c->write_buffer)
+    if (c->write_buffer_size - c->write_buffer_append_offset >=
+        need_to_be_freed)
     {
-      /* The connection is in the sending phase */
-      mhd_assert (MHD_CONNECTION_START_REPLY <= c->state);
-      if (c->write_buffer_size - c->write_buffer_append_offset >= need_to_free)
-      {
-        char *buf;
-        const size_t new_buf_size = c->write_buffer_size - need_to_free;
-        buf = MHD_pool_reallocate (pool,
-                                   c->write_buffer,
-                                   c->write_buffer_size,
-                                   new_buf_size);
-        mhd_assert (c->write_buffer == buf);
-        mhd_assert (c->write_buffer_append_offset <= new_buf_size);
-        mhd_assert (c->write_buffer_send_offset <= new_buf_size);
-        c->write_buffer_size = new_buf_size;
-        c->write_buffer = buf;
-      }
-      else
-        return NULL;
+      char *buf;
+      const size_t new_buf_size = c->write_buffer_size - need_to_be_freed;
+      buf = MHD_pool_reallocate (pool,
+                                 c->write_buffer,
+                                 c->write_buffer_size,
+                                 new_buf_size);
+      mhd_assert (c->write_buffer == buf);
+      mhd_assert (c->write_buffer_append_offset <= new_buf_size);
+      mhd_assert (c->write_buffer_send_offset <= new_buf_size);
+      c->write_buffer_size = new_buf_size;
+      c->write_buffer = buf;
     }
-    else if (NULL != c->read_buffer)
+    else
+      return NULL;
+  }
+  else if (MHD_pool_is_resizable_inplace (pool,
+                                          c->read_buffer,
+                                          c->read_buffer_size))
+  {
+    if (c->read_buffer_size - c->read_buffer_offset >= need_to_be_freed)
     {
-      /* The connection is in the receiving phase */
-      if (c->read_buffer_size - c->read_buffer_offset >= need_to_free)
-      {
-        char *buf;
-        const size_t new_buf_size = c->read_buffer_size - need_to_free;
-        buf = MHD_pool_reallocate (pool,
-                                   c->read_buffer,
-                                   c->read_buffer_size,
-                                   new_buf_size);
-        mhd_assert (c->read_buffer == buf);
-        mhd_assert (c->read_buffer_offset <= new_buf_size);
-        c->read_buffer_size = new_buf_size;
-        c->read_buffer = buf;
-      }
-      else
-        return NULL;
+      char *buf;
+      const size_t new_buf_size = c->read_buffer_size - need_to_be_freed;
+      buf = MHD_pool_reallocate (pool,
+                                 c->read_buffer,
+                                 c->read_buffer_size,
+                                 new_buf_size);
+      mhd_assert (c->read_buffer == buf);
+      mhd_assert (c->read_buffer_offset <= new_buf_size);
+      c->read_buffer_size = new_buf_size;
+      c->read_buffer = buf;
     }
     else
       return NULL;
-    res = MHD_pool_allocate (pool, size, true);
-    mhd_assert (NULL != res); /* It has been checked that pool has enough 
space */
   }
+  else
+    return NULL;
+  res = MHD_pool_allocate (pool, size, true);
+  mhd_assert (NULL != res); /* It has been checked that pool has enough space 
*/
   return res;
 }
 
@@ -1006,41 +1286,6 @@ connection_close_error (struct MHD_Connection 
*connection,
 #endif
 
 
-/**
- * A serious error occurred, check whether error response is already
- * queued and close the connection if response wasn't queued.
- *
- * @param connection connection to close with error
- * @param emsg error message (can be NULL)
- */
-static void
-connection_close_error_check (struct MHD_Connection *connection,
-                              const char *emsg)
-{
-  if ( (NULL != connection->rp.response) &&
-       (400 <= connection->rp.responseCode) &&
-       (NULL == connection->rp.response->crc) && /* Static response only! */
-       (connection->stop_with_error) &&
-       (MHD_CONNECTION_HEADERS_SENDING == connection->state) )
-    return; /* An error response was already queued */
-
-  connection_close_error (connection, emsg);
-}
-
-
-/**
- * Macro to only include error message in call to
- * #connection_close_error_check() if we have HAVE_MESSAGES.
- */
-#ifdef HAVE_MESSAGES
-#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg) \
-  connection_close_error_check (c, emsg)
-#else
-#define CONNECTION_CLOSE_ERROR_CHECK(c, emsg) \
-  connection_close_error_check (c, NULL)
-#endif
-
-
 /**
  * Prepare the response buffer of this connection for
  * sending.  Assumes that the response mutex is
@@ -1195,10 +1440,15 @@ try_ready_chunked_body (struct MHD_Connection 
*connection,
     /* Limit the buffer size to the largest usable size for chunks */
     if ( (max_chunk + max_chunk_overhead) < size)
       size = max_chunk + max_chunk_overhead;
-    connection->write_buffer = MHD_pool_reallocate (connection->pool,
-                                                    connection->write_buffer,
-                                                    connection->
-                                                    write_buffer_size, size);
+    mhd_assert ((NULL == connection->write_buffer) || \
+                MHD_pool_is_resizable_inplace (connection->pool, \
+                                               connection->write_buffer, \
+                                               connection->write_buffer_size));
+    connection->write_buffer =
+      MHD_pool_reallocate (connection->pool,
+                           connection->write_buffer,
+                           connection->write_buffer_size,
+                           size);
     mhd_assert (NULL != connection->write_buffer);
     connection->write_buffer_size = size;
   }
@@ -1528,6 +1778,7 @@ try_grow_read_buffer (struct MHD_Connection *connection,
 {
   size_t new_size;
   size_t avail_size;
+  const size_t def_grow_size = connection->daemon->pool_increment;
   void *rb;
 
   avail_size = MHD_pool_get_free (connection->pool);
@@ -1540,14 +1791,23 @@ try_grow_read_buffer (struct MHD_Connection *connection,
     size_t grow_size;
 
     grow_size = avail_size / 8;
-    if (MHD_BUF_INC_SIZE > grow_size)
+    if (def_grow_size > grow_size)
     {                  /* Shortage of space */
-      if (! required)
-        return false;  /* Grow is not mandatory, leave some space in pool */
+      const size_t left_free =
+        connection->read_buffer_size - connection->read_buffer_offset;
+      mhd_assert (connection->read_buffer_size >= \
+                  connection->read_buffer_offset);
+      if ((def_grow_size <= grow_size + left_free)
+          && (left_free < def_grow_size))
+        grow_size = def_grow_size - left_free;  /* Use precise 'def_grow_size' 
for new free space */
+      else if (! required)
+        return false;                           /* Grow is not mandatory, 
leave some space in pool */
       else
       {
         /* Shortage of space, but grow is mandatory */
-        static const size_t small_inc = MHD_BUF_INC_SIZE / 8;
+        const size_t small_inc =
+          ((MHD_BUF_INC_SIZE > def_grow_size) ?
+           def_grow_size : MHD_BUF_INC_SIZE) / 8;
         if (small_inc < avail_size)
           grow_size = small_inc;
         else
@@ -1556,6 +1816,15 @@ try_grow_read_buffer (struct MHD_Connection *connection,
     }
     new_size = connection->read_buffer_size + grow_size;
   }
+  /* Make sure that read buffer will not be moved */
+  if ((NULL != connection->read_buffer) &&
+      ! MHD_pool_is_resizable_inplace (connection->pool,
+                                       connection->read_buffer,
+                                       connection->read_buffer_size))
+  {
+    mhd_assert (0);
+    return false;
+  }
   /* we can actually grow the buffer, do it! */
   rb = MHD_pool_reallocate (connection->pool,
                             connection->read_buffer,
@@ -1572,6 +1841,7 @@ try_grow_read_buffer (struct MHD_Connection *connection,
     mhd_assert (0);
     return false;
   }
+  mhd_assert (connection->read_buffer == rb);
   connection->read_buffer = rb;
   mhd_assert (NULL != connection->read_buffer);
   connection->read_buffer_size = new_size;
@@ -1605,6 +1875,8 @@ connection_shrink_read_buffer (struct MHD_Connection 
*connection)
   }
   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);
@@ -1618,8 +1890,7 @@ connection_shrink_read_buffer (struct MHD_Connection 
*connection)
  * Allocate the maximum available amount of memory from MemoryPool
  * for write buffer.
  * @param connection the connection whose write buffer is being manipulated
- * @return the size of free space in write buffer, may be smaller
- *         than requested size.
+ * @return the size of the free space in the write buffer
  */
 static size_t
 connection_maximize_write_buffer (struct MHD_Connection *connection)
@@ -1642,6 +1913,9 @@ connection_maximize_write_buffer (struct MHD_Connection 
*connection)
      * 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,
@@ -2387,12 +2661,22 @@ build_connection_chunked_response_footer (struct 
MHD_Connection *connection)
  * @param status_code the response code to send (400, 413 or 414)
  * @param message the error message to send
  * @param message_len the length of the @a message
+ * @param header_name the name of the header, malloc()ed by the caller,
+ *                    free() by this function, optional, can be NULL
+ * @param header_name_len the length of the @a header_name
+ * @param header_value the value of the header, malloc()ed by the caller,
+ *                     free() by this function, optional, can be NULL
+ * @param header_value_len the length of the @a header_value
  */
 static void
 transmit_error_response_len (struct MHD_Connection *connection,
                              unsigned int status_code,
                              const char *message,
-                             size_t message_len)
+                             size_t message_len,
+                             char *header_name,
+                             size_t header_name_len,
+                             char *header_value,
+                             size_t header_value_len)
 {
   struct MHD_Response *response;
   enum MHD_Result iret;
@@ -2459,9 +2743,30 @@ transmit_error_response_len (struct MHD_Connection 
*connection,
     connection->state = MHD_CONNECTION_CLOSED;
     return;
   }
-  iret = MHD_queue_response (connection,
-                             status_code,
-                             response);
+  mhd_assert ((0 == header_name_len) || (NULL != header_name));
+  mhd_assert ((NULL == header_name) || (0 != header_name_len));
+  mhd_assert ((0 == header_value_len) || (NULL != header_value));
+  mhd_assert ((NULL == header_value) || (0 != header_value_len));
+  mhd_assert ((NULL == header_name) || (NULL != header_value));
+  mhd_assert ((NULL != header_value) || (NULL == header_name));
+  if (NULL != header_name)
+  {
+    iret = MHD_add_response_entry_no_alloc_ (response, MHD_HEADER_KIND,
+                                             header_name, header_name_len,
+                                             header_value, header_value_len);
+    if (MHD_NO == iret)
+    {
+      free (header_name);
+      free (header_value);
+    }
+  }
+  else
+    iret = MHD_YES;
+
+  if (MHD_NO != iret)
+    iret = MHD_queue_response (connection,
+                               status_code,
+                               response);
   MHD_destroy_response (response);
   if (MHD_NO == iret)
   {
@@ -2481,8 +2786,6 @@ transmit_error_response_len (struct MHD_Connection 
*connection,
     connection->rq.method = NULL;
     connection->rq.url = NULL;
     connection->rq.url_len = 0;
-    connection->rq.last = NULL;
-    connection->rq.colon = NULL;
     connection->rq.headers_received = NULL;
     connection->rq.headers_received_tail = NULL;
     connection->write_buffer = NULL;
@@ -2513,40 +2816,227 @@ transmit_error_response_len (struct MHD_Connection 
*connection,
  * Transmit static string as error response
  */
 #define transmit_error_response_static(c, code, msg) \
-  transmit_error_response_len (c, code, msg, MHD_STATICSTR_LEN_ (msg))
+  transmit_error_response_len (c, code, \
+                               msg, MHD_STATICSTR_LEN_ (msg), \
+                               NULL, 0, NULL, 0)
 
 /**
- * Update the 'event_loop_info' field of this connection based on the state
- * that the connection is now in.  May also close the connection or
- * perform other updates to the connection if needed to prepare for
- * the next round of the event loop.
+ * Transmit static string as error response and add specified header
+ */
+#define transmit_error_response_header(c, code, m, hd_n, hd_n_l, hd_v, hd_v_l) 
\
+  transmit_error_response_len (c, code, \
+                               m, MHD_STATICSTR_LEN_ (m), \
+                               hd_n, hd_n_l, \
+                               hd_v, hd_v_l)
+
+
+/**
+ * Check whether the read buffer has any upload body data ready to
+ * be processed.
+ * Must be called only when connection is in MHD_CONNECTION_BODY_RECEIVING
+ * state.
  *
- * @param connection connection to get poll set for
+ * @param c the connection to check
+ * @return 'true' if upload body data is already in the read buffer,
+ *         'false' if no upload data is received and not processed.
  */
-static void
-MHD_connection_update_event_loop_info (struct MHD_Connection *connection)
+static bool
+has_unprocessed_upload_body_data_in_buffer (struct MHD_Connection *c)
 {
-  /* Do not update states of suspended connection */
-  if (connection->suspended)
-    return; /* States will be updated after resume. */
-#ifdef HTTPS_SUPPORT
-  if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
-  {   /* HTTPS connection. */
-    switch (connection->tls_state)
+  mhd_assert (MHD_CONNECTION_BODY_RECEIVING == c->state);
+  if (! c->rq.have_chunked_upload)
+    return 0 != c->read_buffer_offset;
+
+  /* Chunked upload */
+  mhd_assert (0 != c->rq.remaining_upload_size); /* Must not be possible in 
MHD_CONNECTION_BODY_RECEIVING state */
+  if (c->rq.current_chunk_offset == c->rq.current_chunk_size)
+  {
+    /* 0 == c->rq.current_chunk_size: Waiting the chunk size (chunk header).
+       0 != c->rq.current_chunk_size: Waiting for chunk-closing CRLF. */
+    return false; /*  */
+  }
+  return 0 != c->read_buffer_offset; /* Chunk payload data in the read buffer 
*/
+}
+
+
+/**
+ * Check whether enough space is available in the read buffer for the next
+ * operation.
+ * Handles grow of the buffer if required and error conditions (when buffer
+ * grow is required but not possible).
+ * Must be called only when processing the event loop states and when
+ * reading is required for the next phase.
+ * @param c the connection to check
+ * @return true if connection handled successfully and enough buffer
+ *         is available,
+ *         false if not enough buffer is available and the loop's states
+ *         must be processed again as connection is in the error state.
+ */
+static bool
+check_and_grow_read_buffer_space (struct MHD_Connection *c)
+{
+  /**
+   * The increase of read buffer size is desirable.
+   */
+  bool rbuff_grow_desired;
+  /**
+   * The increase of read buffer size is a hard requirement.
+   */
+  bool rbuff_grow_required;
+
+  mhd_assert (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info));
+  mhd_assert (! c->discard_request);
+
+  rbuff_grow_required = (c->read_buffer_offset == c->read_buffer_size);
+  if (rbuff_grow_required)
+    rbuff_grow_desired = true;
+  else
+  {
+    rbuff_grow_desired = (c->read_buffer_offset + c->daemon->pool_increment >
+                          c->read_buffer_size);
+
+    if ((rbuff_grow_desired) &&
+        (MHD_CONNECTION_BODY_RECEIVING == c->state))
     {
-    case MHD_TLS_CONN_INIT:
-      connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
-      return;
-    case MHD_TLS_CONN_HANDSHAKING:
-    case MHD_TLS_CONN_WR_CLOSING:
-      if (0 == gnutls_record_get_direction (connection->tls_session))
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+      if (! c->rq.have_chunked_upload)
+      {
+        mhd_assert (MHD_SIZE_UNKNOWN != c->rq.remaining_upload_size);
+        /* Do not grow read buffer more than necessary to process the current
+           request. */
+        rbuff_grow_desired =
+          (c->rq.remaining_upload_size > c->read_buffer_size);
+      }
       else
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
-      return;
-    case MHD_TLS_CONN_CONNECTED:
-      break; /* Do normal processing */
-    case MHD_TLS_CONN_WR_CLOSED:
+      {
+        mhd_assert (MHD_SIZE_UNKNOWN == c->rq.remaining_upload_size);
+        if (0 == c->rq.current_chunk_size)
+          rbuff_grow_desired =  /* Reading value of the next chunk size */
+                               (MHD_CHUNK_HEADER_REASONABLE_LEN >
+                                c->read_buffer_size);
+        else
+        {
+          const size_t cur_chunk_left =
+            c->rq.current_chunk_size - c->rq.current_chunk_offset;
+          /* Do not grow read buffer more than necessary to process the current
+             chunk with terminating CRLF. */
+          mhd_assert (c->rq.current_chunk_offset <= c->rq.current_chunk_size);
+          rbuff_grow_desired = ((cur_chunk_left + 2) > c->read_buffer_size);
+        }
+      }
+    }
+  }
+
+  if (! rbuff_grow_desired)
+    return true; /* No need to increase the buffer */
+
+  if (try_grow_read_buffer (c, rbuff_grow_required))
+    return true; /* Buffer increase succeed */
+
+  if (! rbuff_grow_required)
+    return true; /* Can continue without buffer increase */
+
+  /* Failed to increase the read buffer size, but need to read the data
+     from the network.
+     No more space in the buffer, no more space to increase the buffer. */
+
+  /* 'PROCESS_READ' event state flag must be set only if the last application
+     callback has processed some data. If any data is processed then some
+     space in the read buffer must be available. */
+  mhd_assert (0 == (MHD_EVENT_LOOP_INFO_PROCESS & c->event_loop_info));
+
+  if (MHD_CONNECTION_BODY_RECEIVING != c->state)
+  {
+    /* Receiving request line, request headers or request footers */
+    /* TODO: Improve detection of the conditions */
+    if (c->rq.url != NULL)
+      transmit_error_response_static (c,
+                                      MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
+                                      REQUEST_TOO_BIG);
+    else
+      transmit_error_response_static (c,
+                                      MHD_HTTP_URI_TOO_LONG,
+                                      REQUEST_TOO_BIG);
+    return false;
+  }
+
+  /* Receiving the request body and no space left in the buffer */
+
+  if (! has_unprocessed_upload_body_data_in_buffer (c))
+  {
+    /* Full header is received and no space left for reading
+       the request body.
+       For chunked upload encoding: chunk-extension is too long or
+       chunk size is encoded with excessive number of leading zeros. */
+    /* TODO: report proper cause for the error */
+    transmit_error_response_static (c,
+                                    MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
+                                    REQUEST_TOO_BIG);
+    return false;
+  }
+
+  /* No space left in the buffer but some upload body data can be processed
+     and some space could be freed. */
+  mhd_assert (! c->rq.some_payload_processed);
+  if (0 == (c->daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))
+  {
+    /* The application is handling processing cycles.
+       The data may be processed later. */
+    c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
+    return true;
+  }
+
+  /* Using internal thread for sockets polling */
+
+  /* failed to grow the read buffer, and the
+     client which is supposed to handle the
+     received data in a *blocking* fashion
+     (in this mode) did not handle the data as
+     it was supposed to!
+     => we would either have to do busy-waiting
+     (on the client, which would likely fail),
+     or if we do nothing, we would just timeout
+     on the connection (if a timeout is even
+     set!).
+     Solution: we kill the connection with an error */
+  transmit_error_response_static (c,
+                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                  ERROR_MSG_DATA_NOT_HANDLED_BY_APP);
+  return false;
+}
+
+
+/**
+ * Update the 'event_loop_info' field of this connection based on the state
+ * that the connection is now in.  May also close the connection or
+ * perform other updates to the connection if needed to prepare for
+ * the next round of the event loop.
+ *
+ * @param connection connection to get poll set for
+ */
+static void
+MHD_connection_update_event_loop_info (struct MHD_Connection *connection)
+{
+  /* Do not update states of suspended connection */
+  if (connection->suspended)
+    return; /* States will be updated after resume. */
+#ifdef HTTPS_SUPPORT
+  if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
+  {   /* HTTPS connection. */
+    switch (connection->tls_state)
+    {
+    case MHD_TLS_CONN_INIT:
+      connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+      return;
+    case MHD_TLS_CONN_HANDSHAKING:
+    case MHD_TLS_CONN_WR_CLOSING:
+      if (0 == gnutls_record_get_direction (connection->tls_session))
+        connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+      else
+        connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+      return;
+    case MHD_TLS_CONN_CONNECTED:
+      break; /* Do normal processing */
+    case MHD_TLS_CONN_WR_CLOSED:
     case MHD_TLS_CONN_TLS_FAILED:
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
       return;
@@ -2571,31 +3061,15 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
     {
     case MHD_CONNECTION_INIT:
     case MHD_CONNECTION_REQ_LINE_RECEIVING:
-    case MHD_CONNECTION_URL_RECEIVED:
-    case MHD_CONNECTION_HEADER_PART_RECEIVED:
-      /* while reading headers, we always grow the
-         read buffer if needed, no size-check required */
-      if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
-           (! try_grow_read_buffer (connection, true)) )
-      {
-        if (connection->rq.url != NULL)
-          transmit_error_response_static (connection,
-                                          
MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
-                                          REQUEST_TOO_BIG);
-        else
-          transmit_error_response_static (connection,
-                                          MHD_HTTP_URI_TOO_LONG,
-                                          REQUEST_TOO_BIG);
-        continue;
-      }
-      if (! connection->discard_request)
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
-      else
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
+      connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
       break;
-    case MHD_CONNECTION_HEADERS_RECEIVED:
+    case MHD_CONNECTION_REQ_LINE_RECEIVED:
       mhd_assert (0);
       break;
+    case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
+      connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+      break;
+    case MHD_CONNECTION_HEADERS_RECEIVED:
     case MHD_CONNECTION_HEADERS_PROCESSED:
       mhd_assert (0);
       break;
@@ -2603,54 +3077,37 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
       break;
     case MHD_CONNECTION_BODY_RECEIVING:
-      if (connection->read_buffer_offset == connection->read_buffer_size)
+      if ((connection->rq.some_payload_processed) &&
+          has_unprocessed_upload_body_data_in_buffer (connection))
       {
-        const bool internal_poll = (0 != (connection->daemon->options
-                                          & MHD_USE_INTERNAL_POLLING_THREAD));
-        if ( (! try_grow_read_buffer (connection, true)) &&
-             internal_poll)
+        /* Some data was processed, the buffer must have some free space */
+        mhd_assert (connection->read_buffer_offset < \
+                    connection->read_buffer_size);
+        if (! connection->rq.have_chunked_upload)
         {
-          /* failed to grow the read buffer, and the
-             client which is supposed to handle the
-             received data in a *blocking* fashion
-             (in this mode) did not handle the data as
-             it was supposed to!
-             => we would either have to do busy-waiting
-             (on the client, which would likely fail),
-             or if we do nothing, we would just timeout
-             on the connection (if a timeout is even
-             set!).
-             Solution: we kill the connection with an error */
-          transmit_error_response_static (connection,
-                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                          INTERNAL_ERROR);
-          continue;
+          /* Not a chunked upload. Do not read more than necessary to
+             process the current request. */
+          if (connection->rq.remaining_upload_size >=
+              connection->read_buffer_offset)
+            connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
+          else
+            connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ;
+        }
+        else
+        {
+          /* Chunked upload. The size of the current request is unknown.
+             Continue reading as the space in the read buffer is available. */
+          connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ;
         }
       }
-      if (connection->discard_request)
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
-      else if (connection->read_buffer_offset == connection->read_buffer_size)
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
-      else if (0 == connection->read_buffer_offset)
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
-      else if (connection->rq.some_payload_processed)
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ;
       else
         connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
       break;
     case MHD_CONNECTION_BODY_RECEIVED:
-    case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-      /* while reading footers, we always grow the
-         read buffer if needed, no size-check required */
-      if (connection->read_closed)
-      {
-        CONNECTION_CLOSE_ERROR (connection,
-                                NULL);
-        continue;
-      }
+      mhd_assert (0);
+      break;
+    case MHD_CONNECTION_FOOTERS_RECEIVING:
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
-      /* transition to FOOTERS_RECEIVED
-         happens in read handler */
       break;
     case MHD_CONNECTION_FOOTERS_RECEIVED:
       mhd_assert (0);
@@ -2668,18 +3125,18 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
     case MHD_CONNECTION_HEADERS_SENT:
       mhd_assert (0);
       break;
-    case MHD_CONNECTION_NORMAL_BODY_READY:
-      connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
-      break;
     case MHD_CONNECTION_NORMAL_BODY_UNREADY:
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
       break;
-    case MHD_CONNECTION_CHUNKED_BODY_READY:
+    case MHD_CONNECTION_NORMAL_BODY_READY:
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
       break;
     case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
       break;
+    case MHD_CONNECTION_CHUNKED_BODY_READY:
+      connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
+      break;
     case MHD_CONNECTION_CHUNKED_BODY_SENT:
       mhd_assert (0);
       break;
@@ -2700,83 +3157,18 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
     default:
       mhd_assert (0);
     }
-    break;
-  }
-}
-
-
-/**
- * Parse a single line of the HTTP header.  Advance read_buffer (!)
- * appropriately.  If the current line does not fit, consider growing
- * the buffer.  If the line is far too long, close the connection.  If
- * no line is found (incomplete, buffer too small, line too long),
- * return NULL.  Otherwise return a pointer to the line.
- *
- * @param connection connection we're processing
- * @param[out] line_len pointer to variable that receive
- *             length of line or NULL
- * @return NULL if no full line is available; note that the returned
- *         string will not be 0-termianted
- */
-static char *
-get_next_header_line (struct MHD_Connection *connection,
-                      size_t *line_len)
-{
-  char *rbuf;
-  size_t pos;
-
-  if (0 == connection->read_buffer_offset)
-    return NULL;
-  pos = 0;
-  rbuf = connection->read_buffer;
-  mhd_assert (NULL != rbuf);
 
-  do
-  {
-    const char c = rbuf[pos];
-    bool found;
-    found = false;
-    if ( ('\r' == c) && (pos < connection->read_buffer_offset - 1) &&
-         ('\n' == rbuf[pos + 1]) )
-    { /* Found CRLF */
-      found = true;
-      if (line_len)
-        *line_len = pos;
-      rbuf[pos++] = 0; /* Replace CR with zero */
-      rbuf[pos++] = 0; /* Replace LF with zero */
-    }
-    else if ('\n' == c) /* TODO: Add MHD option to disallow */
-    { /* Found bare LF */
-      found = true;
-      if (line_len)
-        *line_len = pos;
-      rbuf[pos++] = 0; /* Replace LF with zero */
-    }
-    if (found)
+    if (0 != (MHD_EVENT_LOOP_INFO_READ & connection->event_loop_info))
     {
-      connection->read_buffer += pos;
-      connection->read_buffer_size -= pos;
-      connection->read_buffer_offset -= pos;
-      return rbuf;
+      /* Check whether the space is available to receive data */
+      if (! check_and_grow_read_buffer_space (connection))
+      {
+        mhd_assert (connection->discard_request);
+        continue;
+      }
     }
-  } while (++pos < connection->read_buffer_offset);
-
-  /* not found, consider growing... */
-  if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
-       (! try_grow_read_buffer (connection, true)) )
-  {
-    if (NULL != connection->rq.url)
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
-                                      REQUEST_TOO_BIG);
-    else
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_URI_TOO_LONG,
-                                      REQUEST_TOO_BIG);
+    break; /* Everything was processed. */
   }
-  if (line_len)
-    *line_len = 0;
-  return NULL;
 }
 
 
@@ -3163,10 +3555,10 @@ parse_cookie_header (struct MHD_Connection *connection)
  * @param connection the connection
  * @param http_string the pointer to HTTP version string
  * @param len the length of @a http_string in bytes
- * @return #MHD_YES if HTTP version is correct and supported,
- *         #MHD_NO if HTTP version is not correct or unsupported.
+ * @return true if HTTP version is correct and supported,
+ *         false if HTTP version is not correct or unsupported.
  */
-static enum MHD_Result
+static bool
 parse_http_version (struct MHD_Connection *connection,
                     const char *http_string,
                     size_t len)
@@ -3187,7 +3579,7 @@ parse_http_version (struct MHD_Connection *connection,
     transmit_error_response_static (connection,
                                     MHD_HTTP_BAD_REQUEST,
                                     REQUEST_MALFORMED);
-    return MHD_NO;
+    return false;
   }
   if (1 == h[5] - '0')
   {
@@ -3199,7 +3591,7 @@ parse_http_version (struct MHD_Connection *connection,
     else
       connection->rq.http_ver = MHD_HTTP_VER_1_2__1_9;
 
-    return MHD_YES;
+    return true;
   }
 
   if (0 == h[5] - '0')
@@ -3209,14 +3601,14 @@ parse_http_version (struct MHD_Connection *connection,
     transmit_error_response_static (connection,
                                     MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED,
                                     REQ_HTTP_VER_IS_TOO_OLD);
-    return MHD_NO;
+    return false;
   }
 
   connection->rq.http_ver = MHD_HTTP_VER_FUTURE;
   transmit_error_response_static (connection,
                                   MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED,
                                   REQ_HTTP_VER_IS_NOT_SUPPORTED);
-  return MHD_NO;
+  return false;
 }
 
 
@@ -3226,19 +3618,15 @@ parse_http_version (struct MHD_Connection *connection,
  * @param connection the connection
  * @param method the pointer to HTTP request method string
  * @param len the length of @a method in bytes
- * @return #MHD_YES if HTTP method is valid string,
- *         #MHD_NO if HTTP method string is not valid.
  */
-static enum MHD_Result
+static void
 parse_http_std_method (struct MHD_Connection *connection,
                        const char *method,
                        size_t len)
 {
   const char *const m = method; /**< short alias */
   mhd_assert (NULL != m);
-
-  if (0 == len)
-    return MHD_NO;
+  mhd_assert (0 != len);
 
   if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_GET) == len) &&
       (0 == memcmp (m, MHD_HTTP_METHOD_GET, len)))
@@ -3266,141 +3654,6 @@ parse_http_std_method (struct MHD_Connection 
*connection,
     connection->rq.http_mthd = MHD_HTTP_MTHD_TRACE;
   else
     connection->rq.http_mthd = MHD_HTTP_MTHD_OTHER;
-
-  /* Any method string with non-zero length is valid */
-  return MHD_YES;
-}
-
-
-/**
- * Parse the first line of the HTTP HEADER.
- *
- * @param connection the connection (updated)
- * @param line the first line, not 0-terminated
- * @param line_len length of the first @a line
- * @return #MHD_YES if the line is ok, #MHD_NO if it is malformed
- */
-static enum MHD_Result
-parse_initial_message_line (struct MHD_Connection *connection,
-                            char *line,
-                            size_t line_len)
-{
-  struct MHD_Daemon *daemon = connection->daemon;
-  const char *curi;
-  char *uri;
-  char *http_version;
-  char *args;
-
-  if (NULL == (uri = memchr (line,
-                             ' ',
-                             line_len)))
-    return MHD_NO;              /* serious error */
-  uri[0] = '\0';
-  connection->rq.method = line;
-  if (MHD_NO == parse_http_std_method (connection, connection->rq.method,
-                                       (size_t) (uri - line)))
-    return MHD_NO;
-  uri++;
-  /* Skip any spaces. Not required by standard but allow
-     to be more tolerant. */
-  /* TODO: do not skip them in standard mode */
-  while ( (' ' == uri[0]) &&
-          ( (size_t) (uri - line) < line_len) )
-    uri++;
-  if ((size_t) (uri - line) == line_len)
-  {
-    /* No URI and no http version given */
-    curi = "";
-    uri = NULL;
-    connection->rq.version = "";
-    args = NULL;
-    if (MHD_NO == parse_http_version (connection, connection->rq.version, 0))
-      return MHD_NO;
-  }
-  else
-  {
-    size_t uri_len;
-    curi = uri;
-    /* Search from back to accept malformed URI with space */
-    http_version = line + line_len - 1;
-    /* Skip any trailing spaces */
-    /* TODO: do not skip them in standard mode */
-    while ( (' ' == http_version[0]) &&
-            (http_version > uri) )
-      http_version--;
-    /* Find first space in reverse direction */
-    while ( (' ' != http_version[0]) &&
-            (http_version > uri) )
-      http_version--;
-    if (http_version > uri)
-    {
-      /* http_version points to character before HTTP version string */
-      http_version[0] = '\0';
-      connection->rq.version = http_version + 1;
-      if (MHD_NO == parse_http_version (connection, connection->rq.version,
-                                        line_len
-                                        - (size_t)
-                                        (connection->rq.version - line)))
-        return MHD_NO;
-      uri_len = (size_t) (http_version - uri);
-    }
-    else
-    {
-      connection->rq.version = "";
-      if (MHD_NO == parse_http_version (connection, connection->rq.version, 0))
-        return MHD_NO;
-      uri_len = line_len - (size_t) (uri - line);
-    }
-    /* check for spaces in URI if we are "strict" */
-    if ( (-2 < daemon->client_discipline) &&
-         (NULL != memchr (uri,
-                          ' ',
-                          uri_len)) )
-    {
-      /* space exists in URI and we are supposed to be strict, reject */
-      return MHD_NO;
-    }
-
-    args = memchr (uri,
-                   '?',
-                   uri_len);
-  }
-
-  /* log callback before we modify URI *or* args */
-  if (NULL != daemon->uri_log_callback)
-  {
-    connection->rq.client_aware = true;
-    connection->rq.client_context
-      = daemon->uri_log_callback (daemon->uri_log_callback_cls,
-                                  uri,
-                                  connection);
-  }
-
-  if (NULL != args)
-  {
-    args[0] = '\0';
-    args++;
-    /* note that this call clobbers 'args' */
-    MHD_parse_arguments_ (connection,
-                          MHD_GET_ARGUMENT_KIND,
-                          args,
-                          &connection_add_header,
-                          connection);
-  }
-
-  /* unescape URI *after* searching for arguments and log callback */
-  if (NULL != uri)
-  {
-    connection->rq.url_len =
-      daemon->unescape_callback (daemon->unescape_callback_cls,
-                                 connection,
-                                 uri);
-  }
-  else
-    connection->rq.url_len = 0;
-
-  connection->rq.url = curi;
-  return MHD_YES;
 }
 
 
@@ -3455,26 +3708,7 @@ process_request_body (struct MHD_Connection *connection)
   bool instant_retry;
   char *buffer_head;
 
-  connection->rq.some_payload_processed = false;
-
-  if (NULL != connection->rp.response)
-  {
-    /* TODO: discard all read buffer as early response
-     * means that connection have to be closed. */
-    /* already queued a response, discard remaining upload
-       (but not more, there might be another request after it) */
-    size_t purge;
-
-    purge = (size_t) MHD_MIN (connection->rq.remaining_upload_size,
-                              (uint64_t) connection->read_buffer_offset);
-    connection->rq.remaining_upload_size -= purge;
-    if (connection->read_buffer_offset > purge)
-      memmove (connection->read_buffer,
-               &connection->read_buffer[purge],
-               connection->read_buffer_offset - purge);
-    connection->read_buffer_offset -= purge;
-    return;
-  }
+  mhd_assert (NULL == connection->rp.response);
 
   buffer_head = connection->read_buffer;
   available = connection->read_buffer_offset;
@@ -3683,14 +3917,14 @@ process_request_body (struct MHD_Connection *connection)
     if (left_unprocessed > to_be_processed)
       MHD_PANIC (_ ("libmicrohttpd API violation.\n"));
 
-    if (left_unprocessed != to_be_processed)
-      /* Something was processed by the application. */
-      connection->rq.some_payload_processed = true;
+    connection->rq.some_payload_processed =
+      (left_unprocessed != to_be_processed);
+
     if (0 != left_unprocessed)
     {
       instant_retry = false; /* client did not process everything */
 #ifdef HAVE_MESSAGES
-      if ((left_unprocessed == to_be_processed) &&
+      if ((! connection->rq.some_payload_processed) &&
           (! connection->suspended))
       {
         /* client did not process any upload data, complain if
@@ -3705,8 +3939,6 @@ process_request_body (struct MHD_Connection *connection)
 #endif /* HAVE_MESSAGES */
     }
     processed_size = to_be_processed - left_unprocessed;
-    if (connection->rq.have_chunked_upload)
-      connection->rq.current_chunk_offset += processed_size;
     /* dh left "processed" bytes in buffer for next time... */
     buffer_head += processed_size;
     available -= processed_size;
@@ -3716,7 +3948,10 @@ process_request_body (struct MHD_Connection *connection)
       connection->rq.remaining_upload_size -= processed_size;
     }
     else
+    {
       mhd_assert (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size);
+      connection->rq.current_chunk_offset += processed_size;
+    }
   } while (instant_retry);
   /* TODO: zero out reused memory region */
   if ( (available > 0) &&
@@ -3755,150 +3990,6 @@ check_write_done (struct MHD_Connection *connection,
 }
 
 
-/**
- * We have received (possibly the beginning of) a line in the
- * header (or footer).  Validate (check for ":") and prepare
- * to process.
- *
- * @param connection connection we're processing
- * @param line line from the header to process
- * @return #MHD_YES on success, #MHD_NO on error (malformed @a line)
- */
-static enum MHD_Result
-process_header_line (struct MHD_Connection *connection,
-                     char *line)
-{
-  char *colon;
-
-  /* line should be normal header line, find colon */
-  colon = strchr (line, ':');
-  if (NULL == colon)
-  {
-    /* error in header line, die hard */
-    return MHD_NO;
-  }
-  if (-3 < connection->daemon->client_discipline)
-  {
-    /* check for whitespace before colon, which is not allowed
- by RFC 7230 section 3.2.4; we count space ' ' and
- tab '\t', but not '\r\n' as those would have ended the line. */
-    const char *white;
-
-    white = strchr (line, ' ');
-    if ( (NULL != white) &&
-         (white < colon) )
-      return MHD_NO;
-    white = strchr (line, '\t');
-    if ( (NULL != white) &&
-         (white < colon) )
-      return MHD_NO;
-  }
-  /* zero-terminate header */
-  colon[0] = '\0';
-  colon++;                      /* advance to value */
-  while ( ('\0' != colon[0]) &&
-          ( (' ' == colon[0]) ||
-            ('\t' == colon[0]) ) )
-    colon++;
-  /* we do the actual adding of the connection
-     header at the beginning of the while
-     loop since we need to be able to inspect
-     the *next* header line (in case it starts
-     with a space...) */
-  connection->rq.last = line;
-  connection->rq.colon = colon;
-  return MHD_YES;
-}
-
-
-/**
- * Process a header value that spans multiple lines.
- * The previous line(s) are in connection->last.
- *
- * @param connection connection we're processing
- * @param line the current input line
- * @param kind if the line is complete, add a header
- *        of the given kind
- * @return #MHD_YES if the line was processed successfully
- */
-static enum MHD_Result
-process_broken_line (struct MHD_Connection *connection,
-                     char *line,
-                     enum MHD_ValueKind kind)
-{
-  char *last;
-  char *tmp;
-  size_t last_len;
-  size_t tmp_len;
-
-  last = connection->rq.last;
-  if ( (' ' == line[0]) ||
-       ('\t' == line[0]) )
-  {
-    /* value was continued on the next line, see
-       http://www.jmarshall.com/easy/http/ */
-    last_len = strlen (last);
-    /* skip whitespace at start of 2nd line */
-    tmp = line;
-    while ( (' ' == tmp[0]) ||
-            ('\t' == tmp[0]) )
-      tmp++;
-    tmp_len = strlen (tmp);
-    /* FIXME: we might be able to do this better (faster!), as most
-       likely 'last' and 'line' should already be adjacent in
-       memory; however, doing this right gets tricky if we have a
-       value continued over multiple lines (in which case we need to
-       record how often we have done this so we can check for
-       adjacency); also, in the case where these are not adjacent
-       (not sure how it can happen!), we would want to allocate from
-       the end of the pool, so as to not destroy the read-buffer's
-       ability to grow nicely. */
-    last = MHD_pool_reallocate (connection->pool,
-                                last,
-                                last_len + 1,
-                                last_len + tmp_len + 1);
-    if (NULL == last)
-    {
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
-                                      REQUEST_TOO_BIG);
-      return MHD_NO;
-    }
-    memcpy (&last[last_len],
-            tmp,
-            tmp_len + 1);
-    connection->rq.last = last;
-    return MHD_YES;             /* possibly more than 2 lines... */
-  }
-  mhd_assert ( (NULL != last) &&
-               (NULL != connection->rq.colon) );
-  if (MHD_NO ==
-      connection_add_header (connection,
-                             last,
-                             strlen (last),
-                             connection->rq.colon,
-                             strlen (connection->rq.colon),
-                             kind))
-  {
-    /* Error has been queued by connection_add_header() */
-    return MHD_NO;
-  }
-  /* we still have the current line to deal with... */
-  if (0 != line[0])
-  {
-    if (MHD_NO == process_header_line (connection,
-                                       line))
-    {
-      transmit_error_response_static (connection,
-                                      MHD_HTTP_BAD_REQUEST,
-                                      REQUEST_MALFORMED);
-      return MHD_NO;
-    }
-  }
-  return MHD_YES;
-}
-
-
 /**
  * Parse the various headers; figure out the size
  * of the upload and make sure the headers follow
@@ -4044,19 +4135,1435 @@ parse_connection_headers (struct MHD_Connection 
*connection)
 
 
 /**
- * Update the 'last_activity' field of the connection to the current time
- * and move the connection to the head of the 'normal_timeout' list if
- * the timeout for the connection uses the default value.
+ * Reset request header processing state.
  *
- * @param connection the connection that saw some activity
+ * This function resets the processing state before processing the next header
+ * (or footer) line.
+ * @param c the connection to process
  */
-void
-MHD_update_last_activity_ (struct MHD_Connection *connection)
+_MHD_static_inline void
+reset_rq_header_processing_state (struct MHD_Connection *c)
 {
-  struct MHD_Daemon *daemon = connection->daemon;
-#if defined(MHD_USE_THREADS)
-  mhd_assert (NULL == daemon->worker_pool);
-#endif /* MHD_USE_THREADS */
+  memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
+}
+
+
+#ifndef MHD_MAX_EMPTY_LINES_SKIP
+/**
+ * The maximum number of ignored empty line before the request line
+ * at default "strictness" level.
+ */
+#define MHD_MAX_EMPTY_LINES_SKIP 1024
+#endif /* ! MHD_MAX_EMPTY_LINES_SKIP */
+
+/**
+ * Find and parse the request line.
+ * @param c the connection to process
+ * @return true if request line completely processed (or unrecoverable error
+ *         found) and state is changed,
+ *         false if not enough data yet in the receive buffer
+ */
+static bool
+get_request_line_inner (struct MHD_Connection *c)
+{
+  size_t p; /**< The current processing position */
+  const int discp_lvl = c->daemon->client_discipline;
+  /* Allow to skip one or more empty lines before the request line.
+     RFC 9112, section 2.2 */
+  const bool skip_empty_lines = (1 >= discp_lvl);
+  /* Allow to skip more then one empty line before the request line.
+     RFC 9112, section 2.2 */
+  const bool skip_several_empty_lines = (skip_empty_lines && (0 >= discp_lvl));
+  /* Allow to skip number of unlimited empty lines before the request line.
+     RFC 9112, section 2.2 */
+  const bool skip_unlimited_empty_lines =
+    (skip_empty_lines && (-3 >= discp_lvl));
+  /* Treat bare LF as the end of the line.
+     RFC 9112, section 2.2 */
+  const bool bare_lf_as_crlf = (0 >= discp_lvl);
+  /* Treat tab as whitespace delimiter */
+  const bool tab_as_wsp = (0 >= discp_lvl);
+  /* Treat VT (vertical tab) and FF (form feed) as whitespace delimiters */
+  const bool other_wsp_as_wsp = (-1 >= discp_lvl);
+  /* Treat continuous whitespace block as a single space */
+  const bool wsp_blocks = (-1 >= discp_lvl);
+  /* Parse whitespace in URI, special parsing of the request line */
+  const bool wsp_in_uri = (0 >= discp_lvl);
+  /* Keep whitespace in URI, give app URI with whitespace instead of
+     automatic redirect to fixed URI */
+  const bool wsp_in_uri_keep = (-2 >= discp_lvl);
+  /* Keep bare CR character as is.
+     Violates RFC 9112, section 2.2 */
+  const bool bare_cr_keep = (wsp_in_uri_keep && (-3 >= discp_lvl));
+  /* Treat bare CR as space; replace it with space before processing.
+     RFC 9112, section 2.2 */
+  const bool bare_cr_as_sp = ((! bare_cr_keep) && (-1 >= discp_lvl));
+
+  mhd_assert (MHD_CONNECTION_INIT == c->state || \
+              MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+  mhd_assert (NULL == c->rq.method || \
+              MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+  mhd_assert (MHD_HTTP_MTHD_NO_METHOD == c->rq.http_mthd || \
+              MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
+  mhd_assert (MHD_HTTP_MTHD_NO_METHOD == c->rq.http_mthd || \
+              0 != c->rq.hdrs.rq_line.proc_pos);
+
+  if (0 == c->read_buffer_offset)
+  {
+    mhd_assert (MHD_CONNECTION_INIT == c->state);
+    return false; /* No data to process */
+  }
+  p = c->rq.hdrs.rq_line.proc_pos;
+  mhd_assert (p <= c->read_buffer_offset);
+
+  /* Skip empty lines, if any (and if allowed) */
+  /* See RFC 9112, section 2.2 */
+  if ((0 == p)
+      && (skip_empty_lines))
+  {
+    /* Skip empty lines before the request line.
+       See RFC 9112, section 2.2 */
+    bool is_empty_line;
+    mhd_assert (MHD_CONNECTION_INIT == c->state);
+    mhd_assert (NULL == c->rq.method);
+    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 (0 == c->rq.hdrs.rq_line.rq_tgt_len);
+    mhd_assert (NULL == c->rq.version);
+    do
+    {
+      is_empty_line = false;
+      if ('\r' == c->read_buffer[0])
+      {
+        if (1 == c->read_buffer_offset)
+          return false; /* Not enough data yet */
+        if ('\n' == c->read_buffer[1])
+        {
+          is_empty_line = true;
+          c->read_buffer += 2;
+          c->read_buffer_size -= 2;
+          c->read_buffer_offset -= 2;
+          c->rq.hdrs.rq_line.skipped_empty_lines++;
+        }
+      }
+      else if (('\n' == c->read_buffer[0]) &&
+               (bare_lf_as_crlf))
+      {
+        is_empty_line = true;
+        c->read_buffer += 1;
+        c->read_buffer_size -= 1;
+        c->read_buffer_offset -= 1;
+        c->rq.hdrs.rq_line.skipped_empty_lines++;
+      }
+      if (is_empty_line)
+      {
+        if ((! skip_unlimited_empty_lines) &&
+            (((skip_several_empty_lines) ? 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"));
+          return true; /* Process connection closure */
+        }
+        if (0 == c->read_buffer_offset)
+          return false;  /* No more data to process */
+      }
+    } while (is_empty_line);
+  }
+  /* All empty lines are skipped */
+
+  c->state = MHD_CONNECTION_REQ_LINE_RECEIVING;
+  /* Read and parse the request line */
+  mhd_assert (1 <= c->read_buffer_offset);
+
+  while (p < c->read_buffer_offset)
+  {
+    const char chr = c->read_buffer[p];
+    bool end_of_line;
+    /*
+       The processing logic is different depending on the configured 
strictness:
+
+       When whitespace BLOCKS are NOT ALLOWED, the end of the whitespace is
+       processed BEFORE processing of the current character.
+       When whitespace BLOCKS are ALLOWED, the end of the whitespace is
+       processed AFTER processing of the current character.
+
+       When space char in the URI is ALLOWED, the delimiter between the URI and
+       the HTTP version string is processed only at the END of the line.
+       When space in the URI is NOT ALLOWED, the delimiter between the URI and
+       the HTTP version string is processed as soon as the FIRST whitespace is
+       found after URI start.
+     */
+
+    end_of_line = false;
+
+    mhd_assert ((0 == c->rq.hdrs.rq_line.last_ws_end) || \
+                (c->rq.hdrs.rq_line.last_ws_end > \
+                 c->rq.hdrs.rq_line.last_ws_start));
+    mhd_assert ((0 == c->rq.hdrs.rq_line.last_ws_start) || \
+                (0 != c->rq.hdrs.rq_line.last_ws_end));
+
+    /* Check for the end of the line */
+    if ('\r' == chr)
+    {
+      if (p + 1 == c->read_buffer_offset)
+      {
+        c->rq.hdrs.rq_line.proc_pos = p;
+        return false; /* Not enough data yet */
+      }
+      else if ('\n' == c->read_buffer[p + 1])
+        end_of_line = true;
+      else
+      {
+        /* Bare CR alone */
+        /* Must be rejected or replaced with space char.
+           See RFC 9112, section 2.2 */
+        if (bare_cr_as_sp)
+        {
+          c->read_buffer[p] = ' ';
+          c->rq.num_cr_sp_replaced++;
+          continue; /* Re-start processing of the current character */
+        }
+        else if (! bare_cr_keep)
+        {
+          /* A quick simple check whether this line looks like an HTTP request 
*/
+          if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
+              (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
+          {
+            transmit_error_response_static (c,
+                                            MHD_HTTP_BAD_REQUEST,
+                                            BARE_CR_IN_HEADER);
+          }
+          else
+            connection_close_error (c,
+                                    _ ("Bare CR characters are not allowed " \
+                                       "in the request line.\n"));
+          return true; /* Error in the request */
+        }
+      }
+    }
+    else if ('\n' == chr)
+    {
+      /* Bare LF may be recognised as a line delimiter.
+         See RFC 9112, section 2.2 */
+      if (bare_lf_as_crlf)
+        end_of_line = true;
+      else
+      {
+        /* While RFC does not enforce error for bare LF character,
+           if this char is not treated as a line delimiter, it should be
+           rejected to avoid any security weakness due to request smuggling. */
+        /* A quick simple check whether this line looks like an HTTP request */
+        if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
+            (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
+        {
+          transmit_error_response_static (c,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          BARE_LF_IN_HEADER);
+        }
+        else
+          connection_close_error (c,
+                                  _ ("Bare LF characters are not allowed " \
+                                     "in the request line.\n"));
+        return true; /* Error in the request */
+      }
+    }
+
+    if (end_of_line)
+    {
+      /* Handle the end of the request line */
+
+      if (NULL != c->rq.method)
+      {
+        if (wsp_in_uri)
+        {
+          /* The end of the URI and the start of the HTTP version string
+             should be determined now. */
+          mhd_assert (NULL == c->rq.version);
+          mhd_assert (0 == c->rq.hdrs.rq_line.rq_tgt_len);
+          if (0 != c->rq.hdrs.rq_line.last_ws_end)
+          {
+            /* Determine the end and the length of the URI */
+            if (NULL != c->rq.hdrs.rq_line.rq_tgt)
+            {
+              c->read_buffer [c->rq.hdrs.rq_line.last_ws_start] = 0; /* Zero 
terminate the URI */
+              c->rq.hdrs.rq_line.rq_tgt_len =
+                c->rq.hdrs.rq_line.last_ws_start
+                - (size_t) (c->rq.hdrs.rq_line.rq_tgt - c->read_buffer);
+            }
+            else if ((c->rq.hdrs.rq_line.last_ws_start + 1 <
+                      c->rq.hdrs.rq_line.last_ws_end) &&
+                     (HTTP_VER_LEN == (p - c->rq.hdrs.rq_line.last_ws_end)))
+            {
+              /* Found only HTTP method and HTTP version and more than one
+                 whitespace between them. Assume zero-length URI. */
+              mhd_assert (wsp_blocks);
+              c->rq.hdrs.rq_line.last_ws_start++;
+              c->read_buffer[c->rq.hdrs.rq_line.last_ws_start] = 0; /* Zero 
terminate the URI */
+              c->rq.hdrs.rq_line.rq_tgt =
+                c->read_buffer + c->rq.hdrs.rq_line.last_ws_start;
+              c->rq.hdrs.rq_line.rq_tgt_len = 0;
+              c->rq.hdrs.rq_line.num_ws_in_uri = 0;
+              c->rq.hdrs.rq_line.rq_tgt_qmark = NULL;
+            }
+            /* Determine the start of the HTTP version string */
+            if (NULL != c->rq.hdrs.rq_line.rq_tgt)
+            {
+              c->rq.version = c->read_buffer + c->rq.hdrs.rq_line.last_ws_end;
+            }
+          }
+        }
+        else
+        {
+          /* The end of the URI and the start of the HTTP version string
+             should be already known. */
+          if ((NULL == c->rq.version)
+              && (NULL != c->rq.hdrs.rq_line.rq_tgt)
+              && (HTTP_VER_LEN == p - (size_t) (c->rq.hdrs.rq_line.rq_tgt
+                                                - c->read_buffer))
+              && (0 != c->read_buffer[(size_t)
+                                      (c->rq.hdrs.rq_line.rq_tgt
+                                       - c->read_buffer) - 1]))
+          {
+            /* Found only HTTP method and HTTP version and more than one
+               whitespace between them. Assume zero-length URI. */
+            size_t uri_pos;
+            mhd_assert (wsp_blocks);
+            mhd_assert (0 == c->rq.hdrs.rq_line.rq_tgt_len);
+            uri_pos = (size_t) (c->rq.hdrs.rq_line.rq_tgt - c->read_buffer) - 
1;
+            mhd_assert (uri_pos < p);
+            c->rq.version = c->rq.hdrs.rq_line.rq_tgt;
+            c->read_buffer[uri_pos] = 0;  /* Zero terminate the URI */
+            c->rq.hdrs.rq_line.rq_tgt = c->read_buffer + uri_pos;
+            c->rq.hdrs.rq_line.rq_tgt_len = 0;
+            c->rq.hdrs.rq_line.num_ws_in_uri = 0;
+            c->rq.hdrs.rq_line.rq_tgt_qmark = NULL;
+          }
+        }
+
+        if (NULL != c->rq.version)
+        {
+          mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
+          if (! parse_http_version (c, c->rq.version,
+                                    p
+                                    - (size_t) (c->rq.version
+                                                - c->read_buffer)))
+          {
+            mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING < c->state);
+            return true; /* Unsupported / broken HTTP version */
+          }
+          c->read_buffer[p] = 0; /* Zero terminate the HTTP version strings */
+          if ('\r' == chr)
+          {
+            p++; /* Consume CR */
+            mhd_assert (p < c->read_buffer_offset); /* The next character has 
been already checked */
+          }
+          p++; /* Consume LF */
+          c->read_buffer += p;
+          c->read_buffer_size -= p;
+          c->read_buffer_offset -= p;
+          mhd_assert (c->rq.hdrs.rq_line.num_ws_in_uri <= \
+                      c->rq.hdrs.rq_line.rq_tgt_len);
+          mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+                      (0 != c->rq.hdrs.rq_line.rq_tgt_len));
+          mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+                      ((size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark \
+                                 - c->rq.hdrs.rq_line.rq_tgt) < \
+                       c->rq.hdrs.rq_line.rq_tgt_len));
+          mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
+                      (c->rq.hdrs.rq_line.rq_tgt_qmark >= \
+                       c->rq.hdrs.rq_line.rq_tgt));
+          return true; /* The request line is successfully parsed */
+        }
+      }
+      /* Error in the request line */
+
+      /* A quick simple check whether this line looks like an HTTP request */
+      if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
+          (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
+      {
+        transmit_error_response_static (c,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        REQUEST_MALFORMED);
+      }
+      else
+        connection_close_error (c,
+                                _ ("The request line is malformed.\n"));
+
+      return true;
+    }
+
+    /* Process possible end of the previously found whitespace delimiter */
+    if ((! wsp_blocks) &&
+        (p == c->rq.hdrs.rq_line.last_ws_end) &&
+        (0 != c->rq.hdrs.rq_line.last_ws_end))
+    {
+      /* Previous character was a whitespace char and whitespace blocks
+         are not allowed. */
+      /* The current position is the next character after
+         a whitespace delimiter */
+      if (NULL == c->rq.hdrs.rq_line.rq_tgt)
+      {
+        /* The current position is the start of the URI */
+        mhd_assert (0 == c->rq.hdrs.rq_line.rq_tgt_len);
+        mhd_assert (NULL == c->rq.version);
+        c->rq.hdrs.rq_line.rq_tgt = c->read_buffer + p;
+        /* Reset the whitespace marker */
+        c->rq.hdrs.rq_line.last_ws_start = 0;
+        c->rq.hdrs.rq_line.last_ws_end = 0;
+      }
+      else
+      {
+        /* It was a whitespace after the start of the URI */
+        if (! wsp_in_uri)
+        {
+          mhd_assert ((0 != c->rq.hdrs.rq_line.rq_tgt_len) || \
+                      (c->rq.hdrs.rq_line.rq_tgt + 1 == c->read_buffer + p));
+          mhd_assert (NULL == c->rq.version); /* Too many whitespaces? This 
error is handled at whitespace start */
+          c->rq.version = c->read_buffer + p;
+          /* Reset the whitespace marker */
+          c->rq.hdrs.rq_line.last_ws_start = 0;
+          c->rq.hdrs.rq_line.last_ws_end = 0;
+        }
+      }
+    }
+
+    /* Process the current character.
+       Is it not the end of the line.  */
+    if ((' ' == chr)
+        || (('\t' == chr) && (tab_as_wsp))
+        || ((other_wsp_as_wsp) && ((0xb == chr) || (0xc == chr))))
+    {
+      /* A whitespace character */
+      if ((0 == c->rq.hdrs.rq_line.last_ws_end) ||
+          (p != c->rq.hdrs.rq_line.last_ws_end) ||
+          (! wsp_blocks))
+      {
+        /* Found first whitespace char of the new whitespace block */
+        if (NULL == c->rq.method)
+        {
+          /* Found the end of the HTTP method string */
+          mhd_assert (0 == c->rq.hdrs.rq_line.last_ws_start);
+          mhd_assert (0 == c->rq.hdrs.rq_line.last_ws_end);
+          mhd_assert (NULL == c->rq.hdrs.rq_line.rq_tgt);
+          mhd_assert (0 == c->rq.hdrs.rq_line.rq_tgt_len);
+          mhd_assert (NULL == c->rq.version);
+          if (0 == p)
+          {
+            connection_close_error (c,
+                                    _ ("The request line starts with "
+                                       "a whitespace.\n"));
+            return true; /* Error in the request */
+          }
+          c->read_buffer[p] = 0; /* Zero-terminate the request method string */
+          c->rq.method = c->read_buffer;
+          parse_http_std_method (c, c->rq.method, p);
+        }
+        else
+        {
+          /* A whitespace after the start of the URI */
+          if (! wsp_in_uri)
+          {
+            /* Whitespace in URI is not allowed to be parsed */
+            if (NULL == c->rq.version)
+            {
+              mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
+              /* This is a delimiter between URI and HTTP version string */
+              c->read_buffer[p] = 0; /* Zero-terminate request URI string */
+              mhd_assert (((size_t) (c->rq.hdrs.rq_line.rq_tgt   \
+                                     - c->read_buffer)) <= p);
+              c->rq.hdrs.rq_line.rq_tgt_len =
+                p - (size_t) (c->rq.hdrs.rq_line.rq_tgt - c->read_buffer);
+            }
+            else
+            {
+              /* This is a delimiter AFTER version string */
+
+              /* A quick simple check whether this line looks like an HTTP 
request */
+              if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
+                  (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
+              {
+                transmit_error_response_static (c,
+                                                MHD_HTTP_BAD_REQUEST,
+                                                RQ_LINE_TOO_MANY_WSP);
+              }
+              else
+                connection_close_error (c,
+                                        _ ("The request line has more than "
+                                           "two whitespaces.\n"));
+              return true; /* Error in the request */
+            }
+          }
+          else
+          {
+            /* Whitespace in URI is allowed to be parsed */
+            if (0 != c->rq.hdrs.rq_line.last_ws_end)
+            {
+              /* The whitespace after the start of the URI has been found 
already */
+              c->rq.hdrs.rq_line.num_ws_in_uri +=
+                c->rq.hdrs.rq_line.last_ws_end
+                - c->rq.hdrs.rq_line.last_ws_start;
+            }
+          }
+        }
+        c->rq.hdrs.rq_line.last_ws_start = p;
+        c->rq.hdrs.rq_line.last_ws_end = p + 1; /* Will be updated on the next 
char parsing */
+      }
+      else
+      {
+        /* Continuation of the whitespace block */
+        mhd_assert (0 != c->rq.hdrs.rq_line.last_ws_end);
+        mhd_assert (0 != p);
+        c->rq.hdrs.rq_line.last_ws_end = p + 1;
+      }
+    }
+    else
+    {
+      /* Non-whitespace char, not the end of the line */
+      mhd_assert ((0 == c->rq.hdrs.rq_line.last_ws_end) || \
+                  (c->rq.hdrs.rq_line.last_ws_end == p) || \
+                  wsp_in_uri);
+
+      if ((p == c->rq.hdrs.rq_line.last_ws_end) &&
+          (0 != c->rq.hdrs.rq_line.last_ws_end) &&
+          (wsp_blocks))
+      {
+        /* The end of the whitespace block */
+        if (NULL == c->rq.hdrs.rq_line.rq_tgt)
+        {
+          /* This is the first character of the URI */
+          mhd_assert (0 == c->rq.hdrs.rq_line.rq_tgt_len);
+          mhd_assert (NULL == c->rq.version);
+          c->rq.hdrs.rq_line.rq_tgt = c->read_buffer + p;
+          /* Reset the whitespace marker */
+          c->rq.hdrs.rq_line.last_ws_start = 0;
+          c->rq.hdrs.rq_line.last_ws_end = 0;
+        }
+        else
+        {
+          if (! wsp_in_uri)
+          {
+            /* This is the first character of the HTTP version */
+            mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
+            mhd_assert ((0 != c->rq.hdrs.rq_line.rq_tgt_len) || \
+                        (c->rq.hdrs.rq_line.rq_tgt + 1 == c->read_buffer + p));
+            mhd_assert (NULL == c->rq.version); /* Handled at whitespace start 
*/
+            c->rq.version = c->read_buffer + p;
+            /* Reset the whitespace marker */
+            c->rq.hdrs.rq_line.last_ws_start = 0;
+            c->rq.hdrs.rq_line.last_ws_end = 0;
+          }
+        }
+      }
+
+      /* Handle other special characters */
+      if ('?' == chr)
+      {
+        if ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) &&
+            (NULL != c->rq.hdrs.rq_line.rq_tgt))
+        {
+          c->rq.hdrs.rq_line.rq_tgt_qmark = c->read_buffer + p;
+        }
+      }
+      else if ((0xb == chr) || (0xc == chr))
+      {
+        /* VT or LF characters */
+        mhd_assert (! other_wsp_as_wsp);
+        if ((NULL != c->rq.hdrs.rq_line.rq_tgt) &&
+            (NULL == c->rq.version) &&
+            (wsp_in_uri))
+        {
+          c->rq.hdrs.rq_line.num_ws_in_uri++;
+        }
+        else
+        {
+          connection_close_error (c,
+                                  _ ("Invalid character is in the "
+                                     "request line.\n"));
+          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"));
+        return true; /* Error in the request */
+      }
+    }
+
+    p++;
+  }
+
+  c->rq.hdrs.rq_line.proc_pos = p;
+  return false; /* Not enough data yet */
+}
+
+
+#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 *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.hdrs.rq_line.rq_tgt_len);
+  fixed_uri_len = c->rq.hdrs.rq_line.rq_tgt_len
+                  + 2 * c->rq.hdrs.rq_line.num_ws_in_uri;
+  if ((fixed_uri_len + 200 > c->daemon->pool_size) ||
+      (fixed_uri_len > MHD_MAX_FIXED_URI_LEN) ||
+      (NULL == (b = malloc (fixed_uri_len + 1))))
+  {
+    connection_close_error (c,
+                            _ ("The request has whitespace character is " \
+                               "in the URI and the URI is too large to " \
+                               "send automatic redirect to fixed URI.\n"));
+    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.hdrs.rq_line.rq_tgt_len);
+  mhd_assert (fixed_uri_len == o);
+  b[o] = 0; /* Zero-terminate the result */
+
+  hdr_name_len = MHD_STATICSTR_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);
+    transmit_error_response_header (c, MHD_HTTP_MOVED_PERMANENTLY,
+                                    RQ_TARGET_INVALID_CHAR,
+                                    hdr_name, hdr_name_len,
+                                    b, o);
+    return;
+  }
+  free (b);
+  connection_close_error (c,
+                          _ ("The request has whitespace character is in the " 
\
+                             "URI.\n"));
+  return;
+}
+
+
+/**
+ * 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 bool
+process_request_target (struct MHD_Connection *c)
+{
+#if _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.hdrs.rq_line.rq_tgt_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->uri_log_callback)
+  {
+    c->rq.client_aware = true;
+    c->rq.client_context =
+      c->daemon->uri_log_callback (c->daemon->uri_log_callback_cls,
+                                   c->rq.hdrs.rq_line.rq_tgt,
+                                   c);
+  }
+
+  if (NULL != c->rq.hdrs.rq_line.rq_tgt_qmark)
+  {
+#if _DEBUG
+    params_len =
+      c->rq.hdrs.rq_line.rq_tgt_len
+      - (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark - c->rq.hdrs.rq_line.rq_tgt);
+#endif /* _DEBUG */
+    c->rq.hdrs.rq_line.rq_tgt_qmark[0] = 0; /* Replace '?' with zero 
termination */
+    if (MHD_NO == MHD_parse_arguments_ (c,
+                                        MHD_GET_ARGUMENT_KIND,
+                                        c->rq.hdrs.rq_line.rq_tgt_qmark + 1,
+                                        &connection_add_header,
+                                        c))
+    {
+      mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING != c->state);
+      return false;
+    }
+  }
+#if _DEBUG
+  else
+    params_len = 0;
+#endif /* _DEBUG */
+
+  mhd_assert (strlen (c->rq.hdrs.rq_line.rq_tgt) == \
+              c->rq.hdrs.rq_line.rq_tgt_len - params_len);
+
+  /* Finally unescape URI itself */
+  c->rq.url_len =
+    c->daemon->unescape_callback (c->daemon->unescape_callback_cls,
+                                  c,
+                                  c->rq.hdrs.rq_line.rq_tgt);
+  c->rq.url = c->rq.hdrs.rq_line.rq_tgt;
+
+  return true;
+}
+
+
+/**
+ * Find and parse the request line.
+ * Advance to the next state when done, handle errors.
+ * @param c the connection to process
+ * @return true if request line completely processed and state is changed,
+ *         false if not enough data yet in the receive buffer
+ */
+static bool
+get_request_line (struct MHD_Connection *c)
+{
+  const int discp_lvl = c->daemon->client_discipline;
+  /* Parse whitespace in URI, special parsing of the request line */
+  const bool wsp_in_uri = (0 >= discp_lvl);
+  /* Keep whitespace in URI, give app URI with whitespace instead of
+     automatic redirect to fixed URI */
+  const bool wsp_in_uri_keep = (-2 >= discp_lvl);
+
+  if (! get_request_line_inner (c))
+    return false;
+  if (MHD_CONNECTION_REQ_LINE_RECEIVING < c->state)
+    return true; /* Error in the request */
+
+  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);
+  if (0 != c->rq.hdrs.rq_line.num_ws_in_uri)
+  {
+    if (! wsp_in_uri)
+    {
+      transmit_error_response_static (c,
+                                      MHD_HTTP_BAD_REQUEST,
+                                      RQ_TARGET_INVALID_CHAR);
+      return true; /* Error in the request */
+    }
+    if (! wsp_in_uri_keep)
+    {
+      send_redirect_fixed_rq_target (c);
+      return true; /* Error in the request */
+    }
+  }
+  if (! process_request_target (c))
+    return true; /* Error in processing */
+
+  c->state = MHD_CONNECTION_REQ_LINE_RECEIVED;
+  return true;
+}
+
+
+/**
+ * Results of header line reading
+ */
+enum MHD_HdrLineReadRes_
+{
+  /**
+   * Not enough data yet
+   */
+  MHD_HDR_LINE_READING_NEED_MORE_DATA = 0,
+  /**
+   * New header line has been read
+   */
+  MHD_HDR_LINE_READING_GOT_HEADER,
+  /**
+   * Error in header data, error response has been queued
+   */
+  MHD_HDR_LINE_READING_DATA_ERROR,
+  /**
+   * Found the end of the request header (end of field lines)
+   */
+  MHD_HDR_LINE_READING_GOT_END_OF_HEADER
+} _MHD_FIXED_ENUM;
+
+
+/**
+ * Find the end of the request header line and make basic header parsing.
+ * Handle errors and header folding.
+ * @param c the connection to process
+ * @param process_footers if true then footers are processed,
+ *                        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
+ */
+static enum MHD_HdrLineReadRes_
+get_req_header (struct MHD_Connection *c,
+                bool process_footers,
+                struct _MHD_str_w_len *hdr_name,
+                struct _MHD_str_w_len *hdr_value)
+{
+  const int discp_lvl = c->daemon->client_discipline;
+  /* 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 = (0 >= discp_lvl);
+  /* Keep bare CR character as is.
+     Violates RFC 9112, section 2.2-4 */
+  const bool bare_cr_keep = (-3 >= discp_lvl);
+  /* Treat bare CR as space; replace it with space before processing.
+     RFC 9112, section 2.2-4 */
+  const bool bare_cr_as_sp = ((! bare_cr_keep) && (-1 >= discp_lvl));
+  /* Treat NUL as space; replace it with space before processing.
+     RFC 9110, section 5.5-5 */
+  const bool nul_as_sp = (-1 >= discp_lvl);
+  /* Allow folded header lines.
+     RFC 9112, section 5.2-4 */
+  const bool allow_folded = (0 >= discp_lvl);
+  /* Do not reject headers with the whitespace at the start of the first line.
+     When allowed, the first line with whitespace character at the first
+     position is ignored (as well as all possible line foldings of the first
+     line).
+     RFC 9112, section 2.2-8 */
+  const bool allow_wsp_at_start = allow_folded && (-1 >= discp_lvl);
+  /* Allow whitespace in header (field) name.
+     Violates RFC 9110, section 5.1-2 */
+  const bool allow_wsp_in_name = (-2 >= discp_lvl);
+  /* Allow zero-length header (field) name.
+     Violates RFC 9110, section 5.1-2 */
+  const bool allow_empty_name = (-2 >= discp_lvl);
+  /* Allow whitespace before colon.
+     Violates RFC 9112, section 5.1-2 */
+  const bool allow_wsp_before_colon = (-3 >= discp_lvl);
+  /* Do not abort the request when header line has no colon, just skip such
+     bad lines.
+     RFC 9112, section 5-1 */
+  const bool allow_line_without_colon = (-2 >= discp_lvl);
+
+  size_t p; /**< The position of the currently processed character */
+
+#if ! defined (HAVE_MESSAGES) && ! defined(_DEBUG)
+  (void) process_footers; /* Unused parameter */
+#endif /* !HAVE_MESSAGES && !_DEBUG */
+
+  mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
+               MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
+              c->state);
+
+  p = c->rq.hdrs.hdr.proc_pos;
+
+  mhd_assert (p <= c->read_buffer_offset);
+  while (p < c->read_buffer_offset)
+  {
+    const char chr = c->read_buffer[p];
+    bool end_of_line;
+
+    mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || \
+                (c->rq.hdrs.hdr.name_len < p));
+    mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || (0 != p));
+    mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || \
+                (c->rq.hdrs.hdr.name_end_found));
+    mhd_assert ((0 == c->rq.hdrs.hdr.value_start) || \
+                (c->rq.hdrs.hdr.name_len < c->rq.hdrs.hdr.value_start));
+    mhd_assert ((0 == c->rq.hdrs.hdr.value_start) || \
+                (0 != c->rq.hdrs.hdr.name_len));
+    mhd_assert ((0 == c->rq.hdrs.hdr.ws_start) || \
+                (0 == c->rq.hdrs.hdr.name_len) || \
+                (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.name_len));
+    mhd_assert ((0 == c->rq.hdrs.hdr.ws_start) || \
+                (0 == c->rq.hdrs.hdr.value_start) || \
+                (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.value_start));
+
+    /* Check for the end of the line */
+    if ('\r' == chr)
+    {
+      if (0 != p)
+      {
+        /* Line is not empty, need to check for possible line folding */
+        if (p + 2 >= c->read_buffer_offset)
+          break; /* Not enough data yet to check for folded line */
+      }
+      else
+      {
+        /* Line is empty, no need to check for possible line folding */
+        if (p + 2 > c->read_buffer_offset)
+          break; /* Not enough data yet to check for the end of the line */
+      }
+      if ('\n' == c->read_buffer[p + 1])
+        end_of_line = true;
+      else
+      {
+        /* Bare CR alone */
+        /* Must be rejected or replaced with space char.
+           See RFC 9112, section 2.2-4 */
+        if (bare_cr_as_sp)
+        {
+          c->read_buffer[p] = ' ';
+          c->rq.num_cr_sp_replaced++;
+          continue; /* Re-start processing of the current character */
+        }
+        else if (! bare_cr_keep)
+        {
+          transmit_error_response_static (c,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          (! process_footers) ?
+                                          BARE_CR_IN_HEADER :
+                                          BARE_CR_IN_FOOTER);
+          return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+        }
+        end_of_line = false;
+      }
+    }
+    else if ('\n' == chr)
+    {
+      /* Bare LF may be recognised as a line delimiter.
+         See RFC 9112, section 2.2-3 */
+      if (bare_lf_as_crlf)
+      {
+        if (0 != p)
+        {
+          /* Line is not empty, need to check for possible line folding */
+          if (p + 1 >= c->read_buffer_offset)
+            break; /* Not enough data yet to check for folded line */
+        }
+        end_of_line = true;
+      }
+      else
+      {
+        transmit_error_response_static (c,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        (! process_footers) ?
+                                        BARE_LF_IN_HEADER : BARE_LF_IN_FOOTER);
+        return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+      }
+    }
+    else
+      end_of_line = false;
+
+    if (end_of_line)
+    {
+      /* Handle the end of the line */
+      /**
+       *  The full length of the line, including CRLF (or bare LF).
+       */
+      const size_t line_len = p + (('\r' == chr) ? 2 : 1);
+      char next_line_char;
+      mhd_assert (line_len <= c->read_buffer_offset);
+
+      if (0 == p)
+      {
+        /* Zero-length header line. This is the end of the request header
+           section.
+           RFC 9112, Section 2.1-1 */
+        mhd_assert (! c->rq.hdrs.hdr.starts_with_ws);
+        mhd_assert (! c->rq.hdrs.hdr.name_end_found);
+        mhd_assert (0 == c->rq.hdrs.hdr.name_len);
+        mhd_assert (0 == c->rq.hdrs.hdr.ws_start);
+        mhd_assert (0 == c->rq.hdrs.hdr.value_start);
+        /* Consume the line with CRLF (or bare LF) */
+        c->read_buffer += line_len;
+        c->read_buffer_offset -= line_len;
+        c->read_buffer_size -= line_len;
+        return MHD_HDR_LINE_READING_GOT_END_OF_HEADER;
+      }
+
+      mhd_assert (line_len < c->read_buffer_offset);
+      mhd_assert (0 != line_len);
+      mhd_assert ('\n' == c->read_buffer[line_len - 1]);
+      next_line_char = c->read_buffer[line_len];
+      if ((' ' == next_line_char) ||
+          ('\t' == next_line_char))
+      {
+        /* Folded line */
+        if (! allow_folded)
+        {
+          transmit_error_response_static (c,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          (! process_footers) ?
+                                          ERR_RSP_OBS_FOLD :
+                                          ERR_RSP_OBS_FOLD_FOOTER);
+          return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+        }
+        /* Replace CRLF (or bare LF) character(s) with space characters.
+           See RFC 9112, Section 5.2-4 */
+        c->read_buffer[p] = ' ';
+        if ('\r' == chr)
+          c->read_buffer[p + 1] = ' ';
+        continue; /* Re-start processing of the current character */
+      }
+      else
+      {
+        /* It is not a folded line, it's the real end of the non-empty line */
+        bool skip_line = false;
+        mhd_assert (0 != p);
+        if (c->rq.hdrs.hdr.starts_with_ws)
+        {
+          /* This is the first line and it starts with whitespace. This line
+             must be discarded completely.
+             See RFC 9112, Section 2.2-8 */
+          mhd_assert (allow_wsp_at_start);
+#ifdef HAVE_MESSAGES
+          MHD_DLOG (c->daemon,
+                    _ ("Whitespace-prefixed first header line " \
+                       "has been skipped.\n"));
+#endif /* HAVE_MESSAGES */
+          skip_line = true;
+        }
+        else if (! c->rq.hdrs.hdr.name_end_found)
+        {
+          if (! allow_line_without_colon)
+          {
+            transmit_error_response_static (c,
+                                            MHD_HTTP_BAD_REQUEST,
+                                            (! process_footers) ?
+                                            ERR_RSP_HEADER_WITHOUT_COLON :
+                                            ERR_RSP_FOOTER_WITHOUT_COLON);
+            return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+          }
+          /* Skip broken line completely */
+          c->rq.skipped_broken_lines++;
+          skip_line = true;
+        }
+        if (skip_line)
+        {
+          /* Skip the entire line */
+          c->read_buffer += line_len;
+          c->read_buffer_offset -= line_len;
+          c->read_buffer_size -= line_len;
+          p = 0;
+          /* Reset processing state */
+          memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
+          /* Start processing of the next line */
+          continue;
+        }
+        else
+        {
+          /* This line should be valid header line */
+          size_t value_len;
+          mhd_assert ((0 != c->rq.hdrs.hdr.name_len) || allow_empty_name);
+
+          hdr_name->str = c->read_buffer + 0; /* The name always starts at the 
first character */
+          hdr_name->len = c->rq.hdrs.hdr.name_len;
+          mhd_assert (0 == hdr_name->str[hdr_name->len]);
+
+          if (0 == c->rq.hdrs.hdr.value_start)
+          {
+            c->rq.hdrs.hdr.value_start = p;
+            c->read_buffer[p] = 0;
+            value_len = 0;
+          }
+          else if (0 != c->rq.hdrs.hdr.ws_start)
+          {
+            mhd_assert (p > c->rq.hdrs.hdr.ws_start);
+            mhd_assert (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.value_start);
+            c->read_buffer[c->rq.hdrs.hdr.ws_start] = 0;
+            value_len = c->rq.hdrs.hdr.ws_start - c->rq.hdrs.hdr.value_start;
+          }
+          else
+          {
+            mhd_assert (p > c->rq.hdrs.hdr.ws_start);
+            c->read_buffer[p] = 0;
+            value_len = p - c->rq.hdrs.hdr.value_start;
+          }
+          hdr_value->str = c->read_buffer + c->rq.hdrs.hdr.value_start;
+          hdr_value->len = value_len;
+          mhd_assert (0 == hdr_value->str[hdr_value->len]);
+          /* Consume the entire line */
+          c->read_buffer += line_len;
+          c->read_buffer_offset -= line_len;
+          c->read_buffer_size -= line_len;
+          return MHD_HDR_LINE_READING_GOT_HEADER;
+        }
+      }
+    }
+    else if ((' ' == chr) || ('\t' == chr))
+    {
+      if (0 == p)
+      {
+        if (! allow_wsp_at_start)
+        {
+          transmit_error_response_static (c,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          (! process_footers) ?
+                                          ERR_RSP_WSP_BEFORE_HEADER :
+                                          ERR_RSP_WSP_BEFORE_FOOTER);
+          return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+        }
+        c->rq.hdrs.hdr.starts_with_ws = true;
+      }
+      else if ((! c->rq.hdrs.hdr.name_end_found) &&
+               (! c->rq.hdrs.hdr.starts_with_ws))
+      {
+        /* Whitespace in header name / between header name and colon */
+        if (allow_wsp_in_name || allow_wsp_before_colon)
+        {
+          if (0 == c->rq.hdrs.hdr.ws_start)
+            c->rq.hdrs.hdr.ws_start = p;
+        }
+        else
+        {
+          transmit_error_response_static (c,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          (! process_footers) ?
+                                          ERR_RSP_WSP_IN_HEADER_NAME :
+                                          ERR_RSP_WSP_IN_FOOTER_NAME);
+          return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+        }
+      }
+      else
+      {
+        /* Whitespace before/inside/after header (field) value */
+        if (0 == c->rq.hdrs.hdr.ws_start)
+          c->rq.hdrs.hdr.ws_start = p;
+      }
+    }
+    else if (0 == chr)
+    {
+      if (! nul_as_sp)
+      {
+        transmit_error_response_static (c,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        (! process_footers) ?
+                                        ERR_RSP_INVALID_CHR_IN_HEADER :
+                                        ERR_RSP_INVALID_CHR_IN_FOOTER);
+        return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+      }
+      c->read_buffer[p] = ' ';
+      continue; /* Re-start processing of the current character */
+    }
+    else
+    {
+      /* Not a whitespace, not the end of the header line */
+      mhd_assert ('\r' != chr);
+      mhd_assert ('\n' != chr);
+      mhd_assert ('\0' != chr);
+      if ((! c->rq.hdrs.hdr.name_end_found) &&
+          (! c->rq.hdrs.hdr.starts_with_ws))
+      {
+        /* Processing the header (field) name */
+        if (':' == chr)
+        {
+          if (0 == c->rq.hdrs.hdr.ws_start)
+            c->rq.hdrs.hdr.name_len = p;
+          else
+          {
+            mhd_assert (allow_wsp_in_name || allow_wsp_before_colon);
+            if (! allow_wsp_before_colon)
+            {
+              transmit_error_response_static (c,
+                                              MHD_HTTP_BAD_REQUEST,
+                                              (! process_footers) ?
+                                              ERR_RSP_WSP_IN_HEADER_NAME :
+                                              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;
+#ifndef MHD_FAVOR_SMALL_CODE
+            c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
+#endif /* ! MHD_FAVOR_SMALL_CODE */
+          }
+          if ((0 == c->rq.hdrs.hdr.name_len) && ! allow_empty_name)
+          {
+            transmit_error_response_static (c,
+                                            MHD_HTTP_BAD_REQUEST,
+                                            (! process_footers) ?
+                                            ERR_RSP_EMPTY_HEADER_NAME :
+                                            ERR_RSP_EMPTY_FOOTER_NAME);
+            return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
+          }
+          c->rq.hdrs.hdr.name_end_found = true;
+          c->read_buffer[c->rq.hdrs.hdr.name_len] = 0; /* Zero-terminate the 
name */
+        }
+        else
+        {
+          if (0 != c->rq.hdrs.hdr.ws_start)
+          {
+            /* End of the whitespace in header (field) name */
+            mhd_assert (allow_wsp_in_name || allow_wsp_before_colon);
+            if (! allow_wsp_in_name)
+            {
+              transmit_error_response_static (c,
+                                              MHD_HTTP_BAD_REQUEST,
+                                              (! process_footers) ?
+                                              ERR_RSP_WSP_IN_HEADER_NAME :
+                                              ERR_RSP_WSP_IN_FOOTER_NAME);
+              return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request 
*/
+            }
+#ifndef MHD_FAVOR_SMALL_CODE
+            c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
+#endif /* ! MHD_FAVOR_SMALL_CODE */
+          }
+        }
+      }
+      else
+      {
+        /* Processing the header (field) value */
+        if (0 == c->rq.hdrs.hdr.value_start)
+          c->rq.hdrs.hdr.value_start = p;
+#ifndef MHD_FAVOR_SMALL_CODE
+        c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
+#endif /* ! MHD_FAVOR_SMALL_CODE */
+      }
+#ifdef MHD_FAVOR_SMALL_CODE
+      c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
+#endif /* MHD_FAVOR_SMALL_CODE */
+    }
+    p++;
+  }
+  c->rq.hdrs.hdr.proc_pos = p;
+  return MHD_HDR_LINE_READING_NEED_MORE_DATA; /* Not enough data yet */
+}
+
+
+/**
+ * Find the end of the request headers and make basic header parsing.
+ * Advance to the next state when done, handle errors.
+ * @param c the connection to process
+ * @param process_footers if true then footers are processed,
+ *                        if false then headers are processed
+ * @return true if request headers reading finished (either successfully
+ *         or with error),
+ *         false if not enough data yet in the receive buffer
+ */
+static bool
+get_req_headers (struct MHD_Connection *c, bool process_footers)
+{
+  do
+  {
+    struct _MHD_str_w_len hdr_name;
+    struct _MHD_str_w_len hdr_value;
+    enum MHD_HdrLineReadRes_ res;
+
+    mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
+                 MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
+                c->state);
+
+    #ifdef _DEBUG
+    hdr_name.str = NULL;
+    hdr_value.str = NULL;
+#endif /* _DEBUG */
+    res = get_req_header (c, process_footers, &hdr_name, &hdr_value);
+    if (MHD_HDR_LINE_READING_GOT_HEADER == res)
+    {
+      mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
+                   MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
+                  c->state);
+      mhd_assert (NULL != hdr_name.str);
+      mhd_assert (NULL != hdr_value.str);
+      /* Values must be zero-terminated and must not have binary zeros */
+      mhd_assert (strlen (hdr_name.str) == hdr_name.len);
+      mhd_assert (strlen (hdr_value.str) == hdr_value.len);
+      /* Values must not have whitespaces at the start or at the end */
+      mhd_assert ((hdr_name.len == 0) || (hdr_name.str[0] != ' '));
+      mhd_assert ((hdr_name.len == 0) || (hdr_name.str[0] != '\t'));
+      mhd_assert ((hdr_name.len == 0) || \
+                  (hdr_name.str[hdr_name.len - 1] != ' '));
+      mhd_assert ((hdr_name.len == 0) || \
+                  (hdr_name.str[hdr_name.len - 1] != '\t'));
+      mhd_assert ((hdr_value.len == 0) || (hdr_value.str[0] != ' '));
+      mhd_assert ((hdr_value.len == 0) || (hdr_value.str[0] != '\t'));
+      mhd_assert ((hdr_value.len == 0) || \
+                  (hdr_value.str[hdr_value.len - 1] != ' '));
+      mhd_assert ((hdr_value.len == 0) || \
+                  (hdr_value.str[hdr_value.len - 1] != '\t'));
+
+      if (MHD_NO ==
+          MHD_set_connection_value_n_nocheck_ (c,
+                                               (! process_footers) ?
+                                               MHD_HEADER_KIND :
+                                               MHD_FOOTER_KIND,
+                                               hdr_name.str, hdr_name.len,
+                                               hdr_value.str, hdr_value.len))
+      {
+        /**
+         * If 'true' then "headers too large" is used for the error response,
+         * if 'false' then "URI too large is used for the error response.
+         */
+        bool headers_large_err;
+#ifdef HAVE_MESSAGES
+        MHD_DLOG (c->daemon,
+                  _ ("Failed to allocate memory in the connection memory " \
+                     "pool to store %s.\n"),
+                  (! process_footers) ? _ ("header") : _ ("footer"));
+#endif /* HAVE_MESSAGES */
+
+        if (! process_footers)
+        {
+          size_t http_headers_size;
+          size_t url_size;
+          const struct MHD_HTTP_Req_Header *hdr;
+
+          http_headers_size = hdr_name.len + hdr_value.len;
+          url_size = c->rq.url_len;
+          for (hdr = c->rq.headers_received; NULL != hdr; hdr = hdr->next)
+          {
+            if (MHD_HEADER_KIND == hdr->kind)
+              http_headers_size += hdr->header_size + hdr->value_size + 2;
+            else if (MHD_GET_ARGUMENT_KIND == hdr->kind)
+              url_size += hdr->header_size + hdr->value_size + 2;
+          }
+          /* The comparison is not precise as linefeeds (for headers) and
+             unescaping (for GET parameters) are not taken into account,
+             but precision is not required here.  */
+          headers_large_err =
+            (http_headers_size >= url_size);
+        }
+        else
+          headers_large_err = true;
+
+        transmit_error_response_static (c,
+                                        headers_large_err ?
+                                        
MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
+                                        : MHD_HTTP_URI_TOO_LONG,
+                                        REQUEST_TOO_BIG);
+        mhd_assert (MHD_CONNECTION_FULL_REQ_RECEIVED < c->state);
+        return true;
+      }
+      /* Reset processing state */
+      reset_rq_header_processing_state (c);
+      mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
+                   MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
+                  c->state);
+      /* Read the next header (field) line */
+      continue;
+    }
+    else if (MHD_HDR_LINE_READING_NEED_MORE_DATA == res)
+    {
+      mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
+                   MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
+                  c->state);
+      return false;
+    }
+    else if (MHD_HDR_LINE_READING_DATA_ERROR == res)
+    {
+      mhd_assert ((process_footers ? \
+                   MHD_CONNECTION_FOOTERS_RECEIVING : \
+                   MHD_CONNECTION_REQ_HEADERS_RECEIVING) < c->state);
+      mhd_assert (c->stop_with_error);
+      mhd_assert (c->discard_request);
+      return true;
+    }
+    mhd_assert (MHD_HDR_LINE_READING_GOT_END_OF_HEADER == res);
+    break;
+  } while (1);
+
+#ifdef HAVE_MESSAGES
+  if (1 == c->rq.num_cr_sp_replaced)
+  {
+    MHD_DLOG (c->daemon,
+              _ ("One bare CR character has been replaced with space " \
+                 "in %s.\n"),
+              (! process_footers) ?
+              _ ("the request line or in the request headers") :
+              _ ("the request footers"));
+  }
+  else if (0 != c->rq.num_cr_sp_replaced)
+  {
+    MHD_DLOG (c->daemon,
+              _ ("%" PRIu64 " bare CR characters have been replaced with " \
+                 "spaces in the request line and/or in the request %s.\n"),
+              (uint64_t) c->rq.num_cr_sp_replaced,
+              (! process_footers) ? _ ("headers") : _ ("footers"));
+  }
+  if (1 == c->rq.skipped_broken_lines)
+  {
+    MHD_DLOG (c->daemon,
+              _ ("One %s line without colon has been skipped.\n"),
+              (! process_footers) ? _ ("header") : _ ("footer"));
+  }
+  else if (0 != c->rq.skipped_broken_lines)
+  {
+    MHD_DLOG (c->daemon,
+              _ ("%" PRIu64 " %s lines without colons has been skipped.\n"),
+              (uint64_t) c->rq.skipped_broken_lines,
+              (! process_footers) ? _ ("header") : _ ("footer"));
+  }
+#endif /* HAVE_MESSAGES */
+
+  mhd_assert (c->rq.method < c->read_buffer);
+  if (! process_footers)
+  {
+    c->rq.header_size = (size_t) (c->read_buffer - c->rq.method);
+    c->state = MHD_CONNECTION_HEADERS_RECEIVED;
+  }
+  else
+    c->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+  return true;
+}
+
+
+/**
+ * Update the 'last_activity' field of the connection to the current time
+ * and move the connection to the head of the 'normal_timeout' list if
+ * the timeout for the connection uses the default value.
+ *
+ * @param connection the connection that saw some activity
+ */
+void
+MHD_update_last_activity_ (struct MHD_Connection *connection)
+{
+  struct MHD_Daemon *daemon = connection->daemon;
+#if defined(MHD_USE_THREADS)
+  mhd_assert (NULL == daemon->worker_pool);
+#endif /* MHD_USE_THREADS */
 
   if (0 == connection->connection_timeout_ms)
     return;  /* Skip update of activity for connections
@@ -4115,16 +5622,10 @@ MHD_connection_handle_read (struct MHD_Connection 
*connection,
   }
 #endif /* HTTPS_SUPPORT */
 
-  /* make sure "read" has a reasonable number of bytes
-     in buffer to use per system call (if possible) */
-  if (connection->read_buffer_offset + connection->daemon->pool_increment >
-      connection->read_buffer_size)
-    try_grow_read_buffer (connection,
-                          (connection->read_buffer_size ==
-                           connection->read_buffer_offset));
-
+  mhd_assert (NULL != connection->read_buffer);
   if (connection->read_buffer_size == connection->read_buffer_offset)
     return; /* No space for receiving data. */
+
   bytes_read = connection->recv_cls (connection,
                                      &connection->read_buffer
                                      [connection->read_buffer_offset],
@@ -4206,15 +5707,9 @@ MHD_connection_handle_read (struct MHD_Connection 
*connection,
   {
   case MHD_CONNECTION_INIT:
   case MHD_CONNECTION_REQ_LINE_RECEIVING:
-  case MHD_CONNECTION_URL_RECEIVED:
-  case MHD_CONNECTION_HEADER_PART_RECEIVED:
-  case MHD_CONNECTION_HEADERS_RECEIVED:
-  case MHD_CONNECTION_HEADERS_PROCESSED:
-  case MHD_CONNECTION_CONTINUE_SENDING:
+  case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   case MHD_CONNECTION_BODY_RECEIVING:
-  case MHD_CONNECTION_BODY_RECEIVED:
-  case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-  case MHD_CONNECTION_FOOTERS_RECEIVED:
+  case MHD_CONNECTION_FOOTERS_RECEIVING:
   case MHD_CONNECTION_FULL_REQ_RECEIVED:
     /* nothing to do but default action */
     if (connection->read_closed)
@@ -4246,6 +5741,15 @@ MHD_connection_handle_read (struct MHD_Connection 
*connection,
       connection->read_buffer_size = connection->read_buffer_offset;
     }
     break;
+  case MHD_CONNECTION_REQ_LINE_RECEIVED:
+  case MHD_CONNECTION_HEADERS_RECEIVED:
+  case MHD_CONNECTION_HEADERS_PROCESSED:
+  case MHD_CONNECTION_BODY_RECEIVED:
+  case MHD_CONNECTION_FOOTERS_RECEIVED:
+    /* Milestone state, no data should be read */
+    mhd_assert (0); /* Should not be possible */
+    break;
+  case MHD_CONNECTION_CONTINUE_SENDING:
   case MHD_CONNECTION_HEADERS_SENDING:
   case MHD_CONNECTION_HEADERS_SENT:
   case MHD_CONNECTION_NORMAL_BODY_UNREADY:
@@ -4257,6 +5761,7 @@ MHD_connection_handle_read (struct MHD_Connection 
*connection,
   case MHD_CONNECTION_FULL_REPLY_SENT:
   default:
     mhd_assert (0); /* Should not be possible */
+    break;
   }
   return;
 }
@@ -4299,12 +5804,11 @@ MHD_connection_handle_write (struct MHD_Connection 
*connection)
   {
   case MHD_CONNECTION_INIT:
   case MHD_CONNECTION_REQ_LINE_RECEIVING:
-  case MHD_CONNECTION_URL_RECEIVED:
-  case MHD_CONNECTION_HEADER_PART_RECEIVED:
+  case MHD_CONNECTION_REQ_LINE_RECEIVED:
+  case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   case MHD_CONNECTION_HEADERS_RECEIVED:
-    mhd_assert (0);
-    return;
   case MHD_CONNECTION_HEADERS_PROCESSED:
+    mhd_assert (0);
     return;
   case MHD_CONNECTION_CONTINUE_SENDING:
     ret = MHD_send_data_ (connection,
@@ -4337,9 +5841,11 @@ MHD_connection_handle_write (struct MHD_Connection 
*connection)
     return;
   case MHD_CONNECTION_BODY_RECEIVING:
   case MHD_CONNECTION_BODY_RECEIVED:
-  case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+  case MHD_CONNECTION_FOOTERS_RECEIVING:
   case MHD_CONNECTION_FOOTERS_RECEIVED:
   case MHD_CONNECTION_FULL_REQ_RECEIVED:
+    mhd_assert (0);
+    return;
   case MHD_CONNECTION_START_REPLY:
     mhd_assert (0);
     return;
@@ -4729,6 +6235,47 @@ cleanup_connection (struct MHD_Connection *connection)
 }
 
 
+/**
+ * Set initial internal states for the connection to start reading and
+ * processing incoming data.
+ * @param c the connection to process
+ */
+void
+MHD_connection_set_initial_state_ (struct MHD_Connection *c)
+{
+  size_t read_buf_size;
+
+#ifdef HTTPS_SUPPORT
+  mhd_assert ( (0 == (c->daemon->options & MHD_USE_TLS)) || \
+               (MHD_TLS_CONN_INIT == c->tls_state) );
+  mhd_assert ( (0 != (c->daemon->options & MHD_USE_TLS)) || \
+               (MHD_TLS_CONN_NO_TLS == c->tls_state) );
+#endif /* HTTPS_SUPPORT */
+  mhd_assert (MHD_CONNECTION_INIT == c->state);
+
+  c->keepalive = MHD_CONN_KEEPALIVE_UNKOWN;
+  c->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+
+  memset (&c->rq, 0, sizeof(c->rq));
+  memset (&c->rp, 0, sizeof(c->rp));
+
+  c->write_buffer = NULL;
+  c->write_buffer_size = 0;
+  c->write_buffer_send_offset = 0;
+  c->write_buffer_append_offset = 0;
+
+  c->continue_message_write_offset = 0;
+
+  c->read_buffer_offset = 0;
+  read_buf_size = c->daemon->pool_size / 2;
+  c->read_buffer
+    = MHD_pool_allocate (c->pool,
+                         read_buf_size,
+                         false);
+  c->read_buffer_size = read_buf_size;
+}
+
+
 /**
  * Reset connection after request-reply cycle.
  * @param connection the connection to process
@@ -4779,7 +6326,9 @@ connection_reset (struct MHD_Connection *connection,
 
     c->keepalive = MHD_CONN_KEEPALIVE_UNKOWN;
     c->state = MHD_CONNECTION_INIT;
-    c->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+    c->event_loop_info =
+      (0 == c->read_buffer_offset) ?
+      MHD_EVENT_LOOP_INFO_READ : MHD_EVENT_LOOP_INFO_PROCESS;
 
     memset (&c->rq, 0, sizeof(c->rq));
 
@@ -4825,8 +6374,6 @@ enum MHD_Result
 MHD_connection_handle_idle (struct MHD_Connection *connection)
 {
   struct MHD_Daemon *daemon = connection->daemon;
-  char *line;
-  size_t line_len;
   enum MHD_Result ret;
 #ifdef MHD_USE_THREADS
   mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
@@ -4856,103 +6403,29 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     {
     case MHD_CONNECTION_INIT:
     case MHD_CONNECTION_REQ_LINE_RECEIVING:
-      line = get_next_header_line (connection,
-                                   &line_len);
-      if (MHD_CONNECTION_REQ_LINE_RECEIVING < connection->state)
-        continue;
-      if (NULL != line)
-      {
-        /* Check for empty string, as we might want
-           to tolerate 'spurious' empty lines */
-        if (0 == line[0])
-        {
-          /* TODO: Add MHD option to not tolerate it */
-          connection->state = MHD_CONNECTION_INIT;
-          continue; /* Process the next line */
-        }
-        if (MHD_NO == parse_initial_message_line (connection,
-                                                  line,
-                                                  line_len))
-          CONNECTION_CLOSE_ERROR_CHECK (connection,
-                                        NULL);
-        else
-        {
-          mhd_assert (MHD_IS_HTTP_VER_SUPPORTED (connection->rq.http_ver));
-          connection->state = MHD_CONNECTION_URL_RECEIVED;
-        }
-        continue;
-      }
-      /* NULL means we didn't get a full line yet */
-      if (connection->discard_request)
+      if (get_request_line (connection))
       {
-        mhd_assert (MHD_CONNECTION_INIT != connection->state);
+        mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING < connection->state);
+        mhd_assert ((MHD_IS_HTTP_VER_SUPPORTED (connection->rq.http_ver)) \
+                    || (connection->discard_request));
         continue;
       }
-      if (0 < connection->read_buffer_offset)
-        connection->state = MHD_CONNECTION_REQ_LINE_RECEIVING;
+      mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING >= connection->state);
       break;
-    case MHD_CONNECTION_URL_RECEIVED:
-      line = get_next_header_line (connection,
-                                   NULL);
-      if (MHD_CONNECTION_URL_RECEIVED != connection->state)
-        continue;
-      if (NULL == line)
-      {
-        if (connection->read_closed)
-        {
-          CONNECTION_CLOSE_ERROR (connection,
-                                  NULL);
-          continue;
-        }
-        break;
-      }
-      if (0 == line[0])
-      {
-        connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
-        connection->rq.header_size = (size_t) (connection->read_buffer
-                                               - connection->rq.method);
-        continue;
-      }
-      if (MHD_NO == process_header_line (connection,
-                                         line))
-      {
-        transmit_error_response_static (connection,
-                                        MHD_HTTP_BAD_REQUEST,
-                                        REQUEST_MALFORMED);
-        break;
-      }
-      connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
+    case MHD_CONNECTION_REQ_LINE_RECEIVED:
+      reset_rq_header_processing_state (connection);
+      connection->state = MHD_CONNECTION_REQ_HEADERS_RECEIVING;
       continue;
-    case MHD_CONNECTION_HEADER_PART_RECEIVED:
-      line = get_next_header_line (connection,
-                                   NULL);
-      if (MHD_CONNECTION_HEADER_PART_RECEIVED != connection->state)
-        continue;
-      if (NULL == line)
-      {
-        if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
-          continue;
-        if (connection->read_closed)
-        {
-          CONNECTION_CLOSE_ERROR (connection,
-                                  NULL);
-          continue;
-        }
-        break;
-      }
-      if (MHD_NO ==
-          process_broken_line (connection,
-                               line,
-                               MHD_HEADER_KIND))
-        continue;
-      if (0 == line[0])
+    case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
+      if (get_req_headers (connection, false))
       {
-        connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
-        connection->rq.header_size = (size_t) (connection->read_buffer
-                                               - connection->rq.method);
+        mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING < connection->state);
+        mhd_assert ((MHD_CONNECTION_HEADERS_RECEIVED == connection->state) || \
+                    (connection->discard_request));
         continue;
       }
-      continue;
+      mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING == connection->state);
+      break;
     case MHD_CONNECTION_HEADERS_RECEIVED:
       parse_connection_headers (connection);
       if (MHD_CONNECTION_HEADERS_RECEIVED != connection->state)
@@ -5000,89 +6473,53 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       }
       break;
     case MHD_CONNECTION_BODY_RECEIVING:
+      mhd_assert (0 != connection->rq.remaining_upload_size);
+      mhd_assert (! connection->discard_request);
+      mhd_assert (NULL == connection->rp.response);
       if (0 != connection->read_buffer_offset)
       {
         process_request_body (connection);           /* loop call */
         if (MHD_CONNECTION_BODY_RECEIVING != connection->state)
           continue;
       }
-      if ( (0 == connection->rq.remaining_upload_size) ||
-           ( (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size) &&
-             (0 == connection->read_buffer_offset) &&
-             (connection->discard_request) ) )
+      /* Modify here when queueing of the response during data processing
+         will be supported */
+      mhd_assert (! connection->discard_request);
+      mhd_assert (NULL == connection->rp.response);
+      if (0 == connection->rq.remaining_upload_size)
       {
-        if ( (connection->rq.have_chunked_upload) &&
-             (! connection->discard_request) )
-          connection->state = MHD_CONNECTION_BODY_RECEIVED;
-        else
-          connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
-        if (connection->suspended)
-          break;
+        connection->state = MHD_CONNECTION_BODY_RECEIVED;
         continue;
       }
       break;
     case MHD_CONNECTION_BODY_RECEIVED:
-      line = get_next_header_line (connection,
-                                   NULL);
-      if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
-        continue;
-      if (NULL == line)
+      mhd_assert (! connection->discard_request);
+      mhd_assert (NULL == connection->rp.response);
+      if (0 == connection->rq.remaining_upload_size)
       {
-        if (connection->read_closed)
+        if (connection->rq.have_chunked_upload)
         {
-          CONNECTION_CLOSE_ERROR (connection,
-                                  NULL);
-          continue;
+          /* Reset counter variables reused for footers */
+          connection->rq.num_cr_sp_replaced = 0;
+          connection->rq.skipped_broken_lines = 0;
+          reset_rq_header_processing_state (connection);
+          connection->state = MHD_CONNECTION_FOOTERS_RECEIVING;
         }
-        if (0 < connection->read_buffer_offset)
-          connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
-        break;
-      }
-      if (0 == line[0])
-      {
-        connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-        if (connection->suspended)
-          break;
-        continue;
-      }
-      if (MHD_NO == process_header_line (connection,
-                                         line))
-      {
-        transmit_error_response_static (connection,
-                                        MHD_HTTP_BAD_REQUEST,
-                                        REQUEST_MALFORMED);
-        break;
-      }
-      connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
-      continue;
-    case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-      line = get_next_header_line (connection,
-                                   NULL);
-      if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
+        else
+          connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
         continue;
-      if (NULL == line)
-      {
-        if (connection->read_closed)
-        {
-          CONNECTION_CLOSE_ERROR (connection,
-                                  NULL);
-          continue;
-        }
-        break;
       }
-      if (MHD_NO ==
-          process_broken_line (connection,
-                               line,
-                               MHD_FOOTER_KIND))
-        continue;
-      if (0 == line[0])
+      break;
+    case MHD_CONNECTION_FOOTERS_RECEIVING:
+      if (get_req_headers (connection, true))
       {
-        connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-        if (connection->suspended)
-          break;
+        mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING < connection->state);
+        mhd_assert ((MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) || \
+                    (connection->discard_request));
         continue;
       }
-      continue;
+      mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING == connection->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. */
@@ -5536,7 +6973,7 @@ MHD_set_connection_option (struct MHD_Connection 
*connection,
           XDLL_remove (daemon->manual_timeout_head,
                        daemon->manual_timeout_tail,
                        connection);
-        connection->connection_timeout_ms = ui_val * 1000;
+        connection->connection_timeout_ms = ((uint64_t) ui_val) * 1000;
         if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
           XDLL_insert (daemon->normal_timeout_head,
                        daemon->normal_timeout_tail,
diff --git a/src/microhttpd/connection.h b/src/microhttpd/connection.h
index 693e26fc..67a251a8 100644
--- a/src/microhttpd/connection.h
+++ b/src/microhttpd/connection.h
@@ -86,6 +86,14 @@ void
 MHD_set_http_callbacks_ (struct MHD_Connection *connection);
 
 
+/**
+ * Set initial internal states for the connection to start reading and
+ * processing incoming data.
+ * @param c the connection to process
+ */
+void
+MHD_connection_set_initial_state_ (struct MHD_Connection *c);
+
 /**
  * This function handles a particular connection when it has been
  * determined that there is data to be read off a socket. All
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 37df86d1..9b088803 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -2778,6 +2778,7 @@ new_connection_process_ (struct MHD_Daemon *daemon,
     /* Firm check under lock. */
     if (daemon->connections >= daemon->connection_limit)
     { /* Connections limit */
+      MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
 #ifdef HAVE_MESSAGES
       MHD_DLOG (daemon,
                 _ ("Server reached connection limit. "
@@ -2801,6 +2802,9 @@ new_connection_process_ (struct MHD_Daemon *daemon,
                      connection);
       }
       MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+
+      MHD_connection_set_initial_state_ (connection);
+
       if (NULL != daemon->notify_connection)
         daemon->notify_connection (daemon->notify_connection_cls,
                                    connection,
@@ -3662,6 +3666,13 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
   bool sk_spipe_supprs;
   bool sk_cloexec;
   enum MHD_tristate sk_non_ip;
+#if defined(_DEBUG) && defined (USE_ACCEPT4)
+  const bool use_accept4 = ! daemon->avoid_accept4;
+#elif defined (USE_ACCEPT4)
+  static const bool use_accept4 = true;
+#else  /* ! USE_ACCEPT4 && ! _DEBUG */
+  static const bool use_accept4 = false;
+#endif /* ! USE_ACCEPT4 && ! _DEBUG */
 
 #ifdef MHD_USE_THREADS
   mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
@@ -3685,14 +3696,16 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
   sk_nonbl = false;
   sk_spipe_supprs = false;
   sk_cloexec = false;
+  s = MHD_INVALID_SOCKET;
 
 #ifdef USE_ACCEPT4
-  if (MHD_INVALID_SOCKET !=
-      (s = accept4 (fd,
-                    (struct sockaddr *) &addrstorage,
-                    &addrlen,
-                    SOCK_CLOEXEC_OR_ZERO | SOCK_NONBLOCK_OR_ZERO
-                    | SOCK_NOSIGPIPE_OR_ZERO)))
+  if (use_accept4 &&
+      (MHD_INVALID_SOCKET !=
+       (s = accept4 (fd,
+                     (struct sockaddr *) &addrstorage,
+                     &addrlen,
+                     SOCK_CLOEXEC_OR_ZERO | SOCK_NONBLOCK_OR_ZERO
+                     | SOCK_NOSIGPIPE_OR_ZERO))))
   {
     sk_nonbl = (SOCK_NONBLOCK_OR_ZERO != 0);
 #ifndef MHD_WINSOCK_SOCKETS
@@ -3702,11 +3715,13 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
 #endif /* MHD_WINSOCK_SOCKETS */
     sk_cloexec = (SOCK_CLOEXEC_OR_ZERO != 0);
   }
-#else  /* ! USE_ACCEPT4 */
-  if (MHD_INVALID_SOCKET !=
-      (s = accept (fd,
-                   (struct sockaddr *) &addrstorage,
-                   &addrlen)))
+#endif /* USE_ACCEPT4 */
+#if defined(_DEBUG) || ! defined(USE_ACCEPT4)
+  if (! use_accept4 &&
+      (MHD_INVALID_SOCKET !=
+       (s = accept (fd,
+                    (struct sockaddr *) &addrstorage,
+                    &addrlen))))
   {
 #ifdef MHD_ACCEPT_INHERIT_NONBLOCK
     sk_nonbl = daemon->listen_nonblk;
@@ -3720,7 +3735,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
 #endif /* MHD_WINSOCK_SOCKETS */
     sk_cloexec = false;
   }
-#endif /* ! USE_ACCEPT4 */
+#endif /* _DEBUG || !USE_ACCEPT4 */
 
   if (MHD_INVALID_SOCKET == s)
   {
@@ -3778,8 +3793,6 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
   sk_non_ip = daemon->listen_is_unix;
   if (0 >= addrlen)
   {
-    /* Should not happen as 'sockaddr_storage' must be large enough to
-     * store any address supported by the system. */
 #ifdef HAVE_MESSAGES
     if (_MHD_NO != daemon->listen_is_unix)
       MHD_DLOG (daemon,
@@ -5522,7 +5535,7 @@ MHD_run (struct MHD_Daemon *daemon)
 
 
 /**
- * Run websever operation with possible blocking.
+ * Run webserver operation with possible blocking.
  *
  * This function does the following: waits for any network event not more than
  * specified number of milliseconds, processes all incoming and outgoing data,
@@ -6238,10 +6251,41 @@ parse_options_va (struct MHD_Daemon *daemon,
     case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
       daemon->pool_size = va_arg (ap,
                                   size_t);
+      if (64 > daemon->pool_size)
+      {
+#ifdef HAVE_MESSAGES
+        MHD_DLOG (daemon,
+                  _ ("Warning: specified MHD_OPTION_CONNECTION_MEMORY_LIMIT " \
+                     "value is too small and rounded up to 64.\n"));
+#endif /* HAVE_MESSAGES */
+        daemon->pool_size = 64;
+      }
+      if (daemon->pool_size / 4 < daemon->pool_increment)
+        daemon->pool_increment = daemon->pool_size / 4;
       break;
     case MHD_OPTION_CONNECTION_MEMORY_INCREMENT:
       daemon->pool_increment = va_arg (ap,
                                        size_t);
+      if (0 == daemon->pool_increment)
+      {
+#ifdef HAVE_MESSAGES
+        MHD_DLOG (daemon,
+                  _ ("The MHD_OPTION_CONNECTION_MEMORY_INCREMENT value " \
+                     "cannot be zero.\n"));
+#endif /* HAVE_MESSAGES */
+        return MHD_NO;
+      }
+      if (daemon->pool_size / 4 < daemon->pool_increment)
+      {
+#ifdef HAVE_MESSAGES
+        MHD_DLOG (daemon,
+                  _ ("Warning: specified " \
+                     "MHD_OPTION_CONNECTION_MEMORY_INCREMENT value is too " \
+                     "large and rounded down to 1/4 of " \
+                     "MHD_OPTION_CONNECTION_MEMORY_LIMIT.\n"));
+#endif /* HAVE_MESSAGES */
+        daemon->pool_increment = daemon->pool_size / 4;
+      }
       break;
     case MHD_OPTION_CONNECTION_LIMIT:
       daemon->connection_limit = va_arg (ap,
@@ -6264,7 +6308,7 @@ parse_options_va (struct MHD_Daemon *daemon,
         uv = UINT64_MAX / 4000 - 1;
       }
 #endif /* (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT */
-      daemon->connection_timeout_ms = uv * 1000;
+      daemon->connection_timeout_ms = ((uint64_t) uv) * 1000;
       break;
     case MHD_OPTION_NOTIFY_COMPLETED:
       daemon->notify_completed = va_arg (ap,
@@ -7156,6 +7200,9 @@ MHD_start_daemon_va (unsigned int flags,
   /* There is no SIGPIPE on W32, nothing to block. */
   daemon->sigpipe_blocked = true;
 #endif /* _WIN32 && ! __CYGWIN__ */
+#if defined(_DEBUG) && defined(HAVE_ACCEPT4)
+  daemon->avoid_accept4 = false;
+#endif /* _DEBUG */
 
   if ( (0 != (*pflags & MHD_USE_THREAD_PER_CONNECTION)) &&
        (0 == (*pflags & MHD_USE_INTERNAL_POLLING_THREAD)) )
diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c
index 6f80b984..d7d470e8 100644
--- a/src/microhttpd/internal.c
+++ b/src/microhttpd/internal.c
@@ -43,10 +43,10 @@ MHD_state_to_string (enum MHD_CONNECTION_STATE state)
     return "connection init";
   case MHD_CONNECTION_REQ_LINE_RECEIVING:
     return "receiving request line";
-  case MHD_CONNECTION_URL_RECEIVED:
-    return "connection url received";
-  case MHD_CONNECTION_HEADER_PART_RECEIVED:
-    return "header partially received";
+  case MHD_CONNECTION_REQ_LINE_RECEIVED:
+    return "request line received";
+  case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
+    return "headers receiving";
   case MHD_CONNECTION_HEADERS_RECEIVED:
     return "headers received";
   case MHD_CONNECTION_HEADERS_PROCESSED:
@@ -57,8 +57,8 @@ MHD_state_to_string (enum MHD_CONNECTION_STATE state)
     return "body receiving";
   case MHD_CONNECTION_BODY_RECEIVED:
     return "body received";
-  case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-    return "footer partially received";
+  case MHD_CONNECTION_FOOTERS_RECEIVING:
+    return "footers receiving";
   case MHD_CONNECTION_FOOTERS_RECEIVED:
     return "footers received";
   case MHD_CONNECTION_FULL_REQ_RECEIVED:
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 9f5ed442..581f6864 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -1,7 +1,7 @@
 /*
   This file is part of libmicrohttpd
   Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
-  Copyright (C) 2014-2021 Evgeny Grin (Karlson2k)
+  Copyright (C) 2014-2022 Evgeny Grin (Karlson2k)
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -136,8 +136,10 @@
  * IO-buffer, but if absolutely needed we additively grow by the
  * number of bytes given here (up to -- theoretically -- the full pool
  * space).
+ *
+ * Currently set to reasonable maximum MSS size.
  */
-#define MHD_BUF_INC_SIZE 1024
+#define MHD_BUF_INC_SIZE 1500
 
 #ifndef MHD_STATICSTR_LEN_
 /**
@@ -623,21 +625,23 @@ enum MHD_CONNECTION_STATE
 
   /**
    * 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_URL_RECEIVED = MHD_CONNECTION_REQ_LINE_RECEIVING + 1,
+  MHD_CONNECTION_REQ_LINE_RECEIVED = MHD_CONNECTION_REQ_LINE_RECEIVING + 1,
 
   /**
-   * We got part of a multi-line request header.  Wait for the rest.
+   * Receiving request headers.  Wait for the rest of the headers.
    */
-  MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
+  MHD_CONNECTION_REQ_HEADERS_RECEIVING = MHD_CONNECTION_REQ_LINE_RECEIVED + 1,
 
   /**
    * We got the request headers.  Process them.
    */
-  MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
+  MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_REQ_HEADERS_RECEIVING + 1,
 
   /**
-   * We have processed the request headers.  Send 100 continue.
+   * We have processed the request headers.  Call application callback.
    */
   MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
 
@@ -652,20 +656,23 @@ enum MHD_CONNECTION_STATE
   MHD_CONNECTION_BODY_RECEIVING = MHD_CONNECTION_CONTINUE_SENDING + 1,
 
   /**
-   * We got the request body.  Wait for a line of the footer.
+   * 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,
 
   /**
-   * We got part of a line of the footer.  Wait for the
-   * rest.
+   * We are reading the request footers.
    */
-  MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
+  MHD_CONNECTION_FOOTERS_RECEIVING = MHD_CONNECTION_BODY_RECEIVED + 1,
 
   /**
    * We received the entire footer.
+   *
+   * A milestone state. No received data is processed in this state.
    */
-  MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
+  MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTERS_RECEIVING + 1,
 
   /**
    * We received the entire request.
@@ -886,7 +893,7 @@ enum MHD_HTTP_Version
 /**
  * The HTTP method.
  *
- * Only primary methods (specified in RFC7231) are defined here.
+ * Only primary methods (specified in RFC9110) are defined here.
  */
 enum MHD_HTTP_Method
 {
@@ -933,6 +940,111 @@ enum MHD_HTTP_Method
 } _MHD_FIXED_ENUM;
 
 
+/**
+ * The request line processing data
+ */
+struct MHD_RequestLineProcessing
+{
+  /**
+   * The position of the next character to be processed
+   */
+  size_t proc_pos;
+  /**
+   * The number of empty lines skipped
+   */
+  unsigned int skipped_empty_lines;
+  /**
+   * The position of the start of the current/last found whitespace block,
+   * zero if not found yet.
+   */
+  size_t last_ws_start;
+  /**
+   * The position of the next character after the last known whitespace
+   * character in the current/last found whitespace block,
+   * zero if not found yet.
+   */
+  size_t last_ws_end;
+  /**
+   * The pointer to the request target.
+   * The request URI will be formed based on it.
+   */
+  char *rq_tgt;
+  /**
+   * The length of the @a rq_tgt, not including terminating zero.
+   */
+  size_t rq_tgt_len;
+  /**
+   * The pointer to the first question mark in the @a rq_tgt.
+   */
+  char *rq_tgt_qmark;
+  /**
+   * The number of whitespace characters in the request URI
+   */
+  size_t num_ws_in_uri;
+};
+
+/**
+ * The request header processing data
+ */
+struct MHD_HeaderProcessing
+{
+  /**
+   * The position of the last processed character
+   */
+  size_t proc_pos;
+
+  /**
+   * The position of the first whitespace character in current contiguous
+   * whitespace block.
+   * Zero when no whitespace found or found non-whitespace character after
+   * whitespace.
+   * Must be zero, if the current character is not whitespace.
+   */
+  size_t ws_start;
+
+  /**
+   * Indicates that end of the header (field) name found.
+   * Must be false until the first colon in line is found.
+   */
+  bool name_end_found;
+
+  /**
+   * The length of the header name.
+   * Must be zero until the first colon in line is found.
+   * Name always starts at zero position.
+   */
+  size_t name_len;
+
+  /**
+   * The position of the first character of the header value.
+   * Zero when the first character has not been found yet.
+   */
+  size_t value_start;
+
+  /**
+   * Line starts with whitespace.
+   * It's meaningful only for the first line, as other lines should be handled
+   * as "folded".
+   */
+  bool starts_with_ws;
+};
+
+/**
+ * The union of request line and header processing data
+ */
+union MHD_HeadersProcessing
+{
+  /**
+   * The request line processing data
+   */
+  struct MHD_RequestLineProcessing rq_line;
+
+  /**
+   * The request header processing data
+   */
+  struct MHD_HeaderProcessing hdr;
+};
+
 /**
  * Request-specific values.
  *
@@ -1022,14 +1134,19 @@ struct MHD_Request
   uint64_t current_chunk_offset;
 
   /**
-   * Indicate that some of the upload payload data have been processed
-   * by the last call of the connection handler.
+   * Indicate that some of the upload payload data (from the currently
+   * processed chunk for chunked uploads) have been processed by the
+   * last call of the connection handler.
    * If any data have been processed, but some data left in the buffer
    * for further processing, then MHD will use zero timeout before the
-   * next data processing round.
+   * next data processing round. This allow the application handler
+   * process the data by the fixed portions or other way suitable for
+   * application developer.
    * If no data have been processed, than MHD will wait for more data
-   * to come (as it makes no sense to call the connection handler with
-   * the same conditions).
+   * to come (as it makes no sense to call the same connection handler
+   * under the same conditions). However this is dangerous as if buffer
+   * is completely used then connection is aborted. Connection
+   * suspension should be used in such case.
    */
   bool some_payload_processed;
 
@@ -1074,23 +1191,21 @@ struct MHD_Request
    */
   bool dauth_tried;
 #endif /* DAUTH_SUPPORT */
+  /**
+   * Number of bare CR characters that were replaced with space characters
+   * in the request line or in the headers (field lines).
+   */
+  size_t num_cr_sp_replaced;
 
   /**
-   * Last incomplete header line during parsing of headers.
-   * Allocated in pool.  Only valid if state is
-   * either #MHD_CONNECTION_HEADER_PART_RECEIVED or
-   * #MHD_CONNECTION_FOOTER_PART_RECEIVED.
+   * The number of header lines skipped because they have no colon
    */
-  char *last;
+  size_t skipped_broken_lines;
 
   /**
-   * Position after the colon on the last incomplete header
-   * line during parsing of headers.
-   * Allocated in pool.  Only valid if state is
-   * either #MHD_CONNECTION_HEADER_PART_RECEIVED or
-   * #MHD_CONNECTION_FOOTER_PART_RECEIVED.
+   * The data of the request line / request headers processing
    */
-  char *colon;
+  union MHD_HeadersProcessing hdrs;
 };
 
 
@@ -2308,6 +2423,18 @@ struct MHD_Daemon
    * The value to be returned by #MHD_get_daemon_info()
    */
   union MHD_DaemonInfo daemon_info_dummy_port;
+
+#if defined(_DEBUG) && defined(HAVE_ACCEPT4)
+  /**
+   * If set to 'true', accept() function will be used instead of accept4() even
+   * if accept4() is available.
+   * This is a workaround for zzuf, which does not support sockets created
+   * by accept4() function.
+   * There is no API to change the value of this member, it can be flipped
+   * only by direct access to the struct member.
+   */
+  bool avoid_accept4;
+#endif /* _DEBUG */
 };
 
 
diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c
index 8d80f888..fbc94659 100644
--- a/src/microhttpd/memorypool.c
+++ b/src/microhttpd/memorypool.c
@@ -426,6 +426,38 @@ MHD_pool_allocate (struct MemoryPool *pool,
 }
 
 
+/**
+ * Checks whether allocated block is re-sizable in-place.
+ * If block is not re-sizable in-place, it still could be shrunk, but freed
+ * memory will not be re-used until reset of the pool.
+ * @param pool the memory pool to use
+ * @param block the pointer to the allocated block to check
+ * @param block_size the size of the allocated @a block
+ * @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,
+                               size_t block_size)
+{
+  mhd_assert (pool->end >= pool->pos);
+  mhd_assert (pool->size >= pool->end - pool->pos);
+  mhd_assert (block != NULL || block_size == 0);
+  mhd_assert (pool->size >= block_size);
+  if (NULL != block)
+  {
+    const size_t block_offset = mp_ptr_diff_ (block, pool->memory);
+    mhd_assert (mp_ptr_le_ (pool->memory, block));
+    mhd_assert (pool->size >= block_offset);
+    mhd_assert (pool->size >= block_offset + block_size);
+    return (pool->pos ==
+            ROUND_TO_ALIGN_PLUS_RED_ZONE (block_offset + block_size));
+  }
+  return false; /* Unallocated blocks cannot be resized in-place */
+}
+
+
 /**
  * Try to allocate @a size bytes memory area from the @a pool.
  *
diff --git a/src/microhttpd/memorypool.h b/src/microhttpd/memorypool.h
index 49bbcbe1..18c8e63c 100644
--- a/src/microhttpd/memorypool.h
+++ b/src/microhttpd/memorypool.h
@@ -87,6 +87,20 @@ MHD_pool_allocate (struct MemoryPool *pool,
                    size_t size,
                    bool from_end);
 
+/**
+ * Checks whether allocated block is re-sizable in-place.
+ * If block is not re-sizable in-place, it still could be shrunk, but freed
+ * memory will not be re-used until reset of the pool.
+ * @param pool the memory pool to use
+ * @param block the pointer to the allocated block to check
+ * @param block_size the size of the allocated @a block
+ * @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,
+                               size_t block_size);
 
 /**
  * Try to allocate @a size bytes memory area from the @a pool.
diff --git a/src/microhttpd/test_auth_parse.c b/src/microhttpd/test_auth_parse.c
index 8c11499b..459c8286 100644
--- a/src/microhttpd/test_auth_parse.c
+++ b/src/microhttpd/test_auth_parse.c
@@ -160,7 +160,7 @@ MHD_DLOG (const struct MHD_Daemon *daemon,
           ...)
 {
   (void) daemon;
-  if (NULL == conn.rq.last)
+  if (! conn.rq.client_aware)
   {
     fprintf (stderr, "Unexpected call of 'MHD_LOG(), format is '%s'.\n",
              format);
@@ -169,7 +169,7 @@ MHD_DLOG (const struct MHD_Daemon *daemon,
              "NULL" : (conn.rq.headers_received->value));
     mhdErrorExit ();
   }
-  conn.rq.last = NULL; /* Clear the flag */
+  conn.rq.client_aware = false; /* Clear the flag */
   return;
 }
 
@@ -319,7 +319,7 @@ clean_AuthHeaders (void)
 
   conn.read_buffer = NULL;
   conn.write_buffer = NULL;
-  conn.rq.last = NULL;
+  conn.rq.client_aware = false;
 }
 
 
@@ -338,15 +338,14 @@ expect_result_type_n (const char *hdr, size_t hdr_len,
                       int expect_log,
                       unsigned int line_num)
 {
-  static char marker1[] = "Expected log call";
   unsigned int ret;
 
   ret = 0;
   add_AuthHeader (hdr, hdr_len);
   if (expect_log)
-    conn.rq.last = marker1; /* Use like a flag */
+    conn.rq.client_aware = true; /* Use like a flag */
   else
-    conn.rq.last = NULL;
+    conn.rq.client_aware = false;
 #ifdef BAUTH_SUPPORT
   if (MHD_TEST_AUTHTYPE_BASIC == expected_type)
   {
@@ -394,7 +393,7 @@ expect_result_type_n (const char *hdr, size_t hdr_len,
 #endif /* DAUTH_SUPPORT */
   }
 #if defined(BAUTH_SUPPORT) && defined(DAUTH_SUPPORT)
-  if (conn.rq.last)
+  if (conn.rq.client_aware)
   {
     fprintf (stderr,
              "'Authorization' header parsing ERROR:\n"
diff --git a/src/microhttpd/test_mhd_version.c 
b/src/microhttpd/test_mhd_version.c
index 654acf30..bd91d64d 100644
--- a/src/microhttpd/test_mhd_version.c
+++ b/src/microhttpd/test_mhd_version.c
@@ -18,7 +18,7 @@
 */
 
 /**
- * @file microhttpd/test_mhd_version.h
+ * @file microhttpd/test_mhd_version.с
  * @brief  Tests for MHD versions identifiers
  * @author Karlson2k (Evgeny Grin)
  */
@@ -103,16 +103,22 @@ test_macro2_vs_func_str (void)
 static int
 test_func_str_vs_macro_bin (void)
 {
-#ifdef HAVE_SNPRINTF
-  char bin_print[10];
+  char bin_print[64];
   int res;
   const char *str_func = MHD_get_version ();
 
   printf ("Checking MHD_get_version() function vs MHD_VERSION macro.\n");
+#ifdef HAVE_SNPRINTF
   res = snprintf (bin_print, sizeof(bin_print), "%X.%X.%X",
                   (unsigned int) ((bin_macro >> 24) & 0xFF),
                   (unsigned int) ((bin_macro >> 16) & 0xFF),
                   (unsigned int) ((bin_macro >> 8) & 0xFF));
+#else  /* ! HAVE_SNPRINTF */
+  res = sprintf (bin_print, "%X.%X.%X",
+                 (unsigned int) ((bin_macro >> 24) & 0xFF),
+                 (unsigned int) ((bin_macro >> 16) & 0xFF),
+                 (unsigned int) ((bin_macro >> 8) & 0xFF));
+#endif /* ! HAVE_SNPRINTF */
   if ((9 < res) || (0 >= res))
   {
     fprintf (stderr, "snprintf() error.\n");
@@ -132,11 +138,6 @@ test_func_str_vs_macro_bin (void)
            bin_macro,
            bin_print);
   return 0;
-#else  /* ! HAVE_SNPRINTF */
-  fprintf (stderr, "snprintf() function is not available. "
-           "Cannot check binary/string match.\n");
-  return 0;
-#endif /* ! HAVE_SNPRINTF */
 }
 
 
@@ -219,5 +220,11 @@ main (void)
   res += test_macro_vs_func_bin ();
   res += test_func_bin_format ();
 
-  return 0 == res ? 0 : 1;
+  if (0 != res)
+  {
+    fprintf (stderr, "Test failed. Number of errors: %d\n", res);
+    return 1;
+  }
+  printf ("Test succeed.\n");
+  return 0;
 }
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index 834c0775..f4ca1974 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -137,6 +137,16 @@ check_PROGRAMS = \
   test_get_chunked_close_empty_forced \
   test_put_chunked \
   test_callback \
+  test_get_header_fold \
+  test_put_header_fold \
+  test_put_large_header_fold \
+  test_put_header_fold_last \
+  test_put_header_fold_large \
+  test_get_header_double_fold \
+  test_put_header_double_fold \
+  test_put_large_header_double_fold \
+  test_put_header_double_fold_last \
+  test_put_header_double_fold_large \
   $(EMPTY_ITEM)
 
 if ENABLE_COOKIE
@@ -629,3 +639,24 @@ test_put_broken_len_SOURCES = \
   test_put_broken_len.c mhd_has_in_name.h mhd_has_param.h
 
 test_put_broken_len10_SOURCES = $(test_put_broken_len_SOURCES)
+
+test_put_header_fold_SOURCES = \
+  test_put_header_fold.c mhd_has_in_name.h mhd_has_param.h
+
+test_put_large_header_fold_SOURCES = $(test_put_header_fold_SOURCES)
+
+test_get_header_fold_SOURCES = $(test_put_header_fold_SOURCES)
+
+test_put_header_fold_last_SOURCES = $(test_put_header_fold_SOURCES)
+
+test_put_header_fold_large_SOURCES = $(test_put_header_fold_SOURCES)
+
+test_put_header_double_fold_SOURCES = $(test_put_header_fold_SOURCES)
+
+test_put_large_header_double_fold_SOURCES = 
$(test_put_large_header_fold_SOURCES)
+
+test_get_header_double_fold_SOURCES = $(test_put_header_fold_SOURCES)
+
+test_put_header_double_fold_last_SOURCES = $(test_put_header_fold_last_SOURCES)
+
+test_put_header_double_fold_large_SOURCES = 
$(test_put_header_fold_large_SOURCES)
diff --git a/src/testcurl/test_long_header.c b/src/testcurl/test_long_header.c
index a423d3b5..0f679d63 100644
--- a/src/testcurl/test_long_header.c
+++ b/src/testcurl/test_long_header.c
@@ -304,6 +304,8 @@ main (int argc, char *const *argv)
   errorCount += testLongHeaderGet (VERY_LONG / 2 + 1893);
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
+  else
+    printf ("Test succeed.\n");
   curl_global_cleanup ();
   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
 }
diff --git a/src/testcurl/test_head.c b/src/testcurl/test_put_header_fold.c
similarity index 54%
copy from src/testcurl/test_head.c
copy to src/testcurl/test_put_header_fold.c
index 9458f8a0..dbfe3f25 100644
--- a/src/testcurl/test_head.c
+++ b/src/testcurl/test_put_header_fold.c
@@ -20,8 +20,8 @@
 */
 
 /**
- * @file testcurl/test_head.c
- * @brief  Testcase for HEAD requests
+ * @file testcurl/test_put_header_fold.c
+ * @brief  Testcase for requests with header fold
  * @author Karlson2k (Evgeny Grin)
  */
 
@@ -36,13 +36,35 @@
 #ifndef _WIN32
 #include <sys/socket.h>
 #include <unistd.h>
-#else
-#include <wincrypt.h>
 #endif
 
+#include "internal.h"
 #include "mhd_has_param.h"
 #include "mhd_has_in_name.h"
 
+/* The next macros are borrowed from memorypool.c
+   Keep them in sync! */
+
+/**
+ * Align to 2x word size (as GNU libc does).
+ */
+#define ALIGN_SIZE (2 * sizeof(void*))
+/**
+ * Round up 'n' to a multiple of ALIGN_SIZE.
+ */
+#define ROUND_TO_ALIGN(n) (((n) + (ALIGN_SIZE - 1)) \
+                           / (ALIGN_SIZE) *(ALIGN_SIZE))
+#ifndef MHD_ASAN_POISON_ACTIVE
+#define _MHD_RED_ZONE_SIZE (0)
+#else  /* MHD_ASAN_POISON_ACTIVE */
+#define _MHD_RED_ZONE_SIZE (ALIGN_SIZE)
+#endif /* MHD_ASAN_POISON_ACTIVE */
+
+#define ROUND_TO_ALIGN_PLUS_RED_ZONE(n) (ROUND_TO_ALIGN(n) + 
_MHD_RED_ZONE_SIZE)
+
+/* The previous macros are borrowed from memorypool.c
+   Keep them in sync! */
+
 #ifndef MHD_STATICSTR_LEN_
 /**
  * Determine length of static string / macro strings at compile time.
@@ -192,38 +214,175 @@ _mhdErrorExit_func (const char *errDesc, const char 
*funcName, int lineNum)
 /* Could be increased to facilitate debugging */
 #define TIMEOUTS_VAL 5
 
-#define EXPECTED_URI_BASE_PATH  "/"
+#define TEST_UPLOAD_DATA_SIZE 2048U
 
-#define EXISTING_URI  EXPECTED_URI_BASE_PATH
-
-#define EXPECTED_URI_BASE_PATH_MISSING  "/wrong_uri"
+#define EXPECTED_URI_BASE_PATH  "/"
 
 #define URL_SCHEME "http:/" "/"
 
 #define URL_HOST "127.0.0.1"
 
-#define URL_SCHEME_HOST URL_SCHEME URL_HOST
+#define URL_SCHEME_HOST_PATH URL_SCHEME URL_HOST EXPECTED_URI_BASE_PATH
+
+#define RP_HEADER1_NAME "First"
+#define RP_HEADER1_VALUE "1st"
+#define RP_HEADER1 RP_HEADER1_NAME ": " RP_HEADER1_VALUE
+#define RP_HEADER1_CRLF RP_HEADER1 "\r\n"
+#define RP_HEADER2_NAME "Normal"
+#define RP_HEADER2_VALUE "it's fine"
+#define RP_HEADER2 RP_HEADER2_NAME ": " RP_HEADER2_VALUE
+#define RP_HEADER2_CRLF RP_HEADER2 "\r\n"
+
+#define HDR_FOLD "\r\n "
+#define RQ_HEADER1_NAME RP_HEADER1_NAME
+#define RQ_HEADER1_VALUE RP_HEADER1_VALUE
+#define RQ_HEADER1 RQ_HEADER1_NAME ": " RQ_HEADER1_VALUE
+#define RQ_HEADER2_NAME "Folded"
+#define RQ_HEADER2_VALUE_S "start"
+#define RQ_HEADER2_VALUE_E "end"
+#define RQ_HEADER2_VALUE \
+  RQ_HEADER2_VALUE_S HDR_FOLD RQ_HEADER2_VALUE_E
+#define RQ_HEADER2_VALUE_DF \
+  RQ_HEADER2_VALUE_S HDR_FOLD HDR_FOLD RQ_HEADER2_VALUE_E
+#define RQ_HEADER2 RQ_HEADER2_NAME ": " RQ_HEADER2_VALUE
+#define RQ_HEADER2_DF RQ_HEADER2_NAME ": " RQ_HEADER2_VALUE_DF
+#define RQ_HEADER3_NAME RP_HEADER2_NAME
+#define RQ_HEADER3_VALUE RP_HEADER2_VALUE
+#define RQ_HEADER3 RQ_HEADER3_NAME ": " RQ_HEADER3_VALUE
 
-#define HEADER1_NAME "First"
-#define HEADER1_VALUE "1st"
-#define HEADER1 HEADER1_NAME ": " HEADER1_VALUE
-#define HEADER1_CRLF HEADER1 "\r\n"
-#define HEADER2_NAME "Normal"
-#define HEADER2_VALUE "it's fine"
-#define HEADER2 HEADER2_NAME ": " HEADER2_VALUE
-#define HEADER2_CRLF HEADER2 "\r\n"
+/**
+ * The number of request headers: 3 custom headers + 2 automatic headers
+ */
+#define RQ_NUM_HEADERS (3 + 2)
+/**
+ * The extra size in the memory pool for pointers to the headers
+ */
+#define HEADERS_POINTERS_SIZE \
+  RQ_NUM_HEADERS * \
+  ROUND_TO_ALIGN_PLUS_RED_ZONE(sizeof(struct MHD_HTTP_Req_Header))
 
 #define PAGE \
   "<html><head><title>libmicrohttpd demo page</title></head>" \
   "<body>Success!</body></html>"
 
-#define PAGE_404 \
-  "<html><head><title>404 error</title></head>" \
-  "<body>Error 404: The requested URI does not exist</body></html>"
-
 /* Global parameters */
 static int verbose;
 static int oneone;                  /**< If false use HTTP/1.0 for requests*/
+static int use_get;
+static int use_put;
+static int use_put_large;
+static int use_double_fold;
+static int use_hdr_last; /**< If non-zero, folded header is placed last */
+static int use_hdr_large; /**< If non-zero, folded header is large */
+
+/* Static data */
+static struct curl_slist *libcurl_headers = NULL;
+
+static char *put_data = NULL;
+
+/**
+ * Initialise headers for libcurl
+ *
+ * @return non-zero if succeed,
+ *         zero if failed
+ */
+static void
+libcurl_headers_init (void)
+{
+  libcurl_headers = curl_slist_append (NULL, RQ_HEADER1);
+  if (NULL == libcurl_headers)
+    libcurlErrorExitDesc ("curl_slist_append() failed");
+
+  if (use_hdr_last)
+  {
+    libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER3);
+    if (NULL == libcurl_headers)
+      libcurlErrorExitDesc ("curl_slist_append() failed");
+  }
+
+  if (! use_hdr_large)
+  {
+    if (! use_double_fold)
+      libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER2);
+    else
+      libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER2_DF);
+    if (NULL == libcurl_headers)
+      libcurlErrorExitDesc ("curl_slist_append() failed");
+  }
+  else
+  {
+    char *buf;
+    size_t pos;
+    buf = malloc (TEST_UPLOAD_DATA_SIZE + 1);
+    if (NULL == buf)
+      externalErrorExitDesc ("malloc() failed");
+    pos = 0;
+    memcpy (buf, RQ_HEADER2_NAME, MHD_STATICSTR_LEN_ (RQ_HEADER2_NAME));
+    pos += MHD_STATICSTR_LEN_ (RQ_HEADER2_NAME);
+    buf[pos++] = ':';
+    buf[pos++] = ' ';
+    memcpy (buf + pos,
+            RQ_HEADER2_VALUE_S, MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S));
+    pos += MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S);
+    memcpy (buf + pos, HDR_FOLD, MHD_STATICSTR_LEN_ (HDR_FOLD));
+    pos += MHD_STATICSTR_LEN_ (HDR_FOLD);
+    if (use_double_fold)
+    {
+      memcpy (buf + pos, HDR_FOLD, MHD_STATICSTR_LEN_ (HDR_FOLD));
+      pos += MHD_STATICSTR_LEN_ (HDR_FOLD);
+    }
+    memset (buf + pos, 'a',
+            TEST_UPLOAD_DATA_SIZE - pos
+            - MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E) - 1);
+    pos += TEST_UPLOAD_DATA_SIZE - pos
+           - MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E) - 1;
+    buf[pos++] = ' ';
+    memcpy (buf + pos,
+            RQ_HEADER2_VALUE_E, MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E));
+    pos += MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E);
+    if (TEST_UPLOAD_DATA_SIZE != pos)
+      externalErrorExitDesc ("Position miscalculation");
+    buf[pos] = 0;
+
+    libcurl_headers = curl_slist_append (libcurl_headers, buf);
+    if (NULL == libcurl_headers)
+      libcurlErrorExitDesc ("curl_slist_append() failed");
+
+    free (buf);
+  }
+
+  if (! use_hdr_last)
+  {
+    libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER3);
+    if (NULL == libcurl_headers)
+      libcurlErrorExitDesc ("curl_slist_append() failed");
+  }
+}
+
+
+static void
+init_put_data (void)
+{
+  size_t i;
+  put_data = malloc (TEST_UPLOAD_DATA_SIZE + 1);
+  if (NULL == put_data)
+    externalErrorExit ();
+
+  for (i = 0; i < (TEST_UPLOAD_DATA_SIZE - 1); ++i)
+  {
+    if (0 == (i % 7))
+      put_data[i] = ' ';
+    else if (0 == (i % 47))
+      put_data[i] = '\n';
+    else if (0 == (i % 11))
+      put_data[i] = (char) ('A' + i % ('Z' - 'A' + 1));
+    else
+      put_data[i] = (char) ('a' + i % ('z' - 'a' + 1));
+  }
+  put_data[TEST_UPLOAD_DATA_SIZE - 1] = '\n';
+  put_data[TEST_UPLOAD_DATA_SIZE] = 0;
+}
+
 
 static void
 test_global_init (void)
@@ -232,13 +391,20 @@ test_global_init (void)
 
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     externalErrorExit ();
+
+  init_put_data ();
+  libcurl_headers_init ();
 }
 
 
 static void
 test_global_cleanup (void)
 {
+  curl_slist_free_all (libcurl_headers);
   curl_global_cleanup ();
+  if (NULL != put_data)
+    free (put_data);
+  put_data = NULL;
 }
 
 
@@ -247,7 +413,8 @@ struct headers_check_result
   unsigned int expected_size;
   int header1_found;
   int header2_found;
-  int size_found;
+  unsigned int size_found;
+  unsigned int size_broken_found;
 };
 
 static size_t
@@ -258,11 +425,11 @@ lcurl_hdr_callback (char *buffer, size_t size, size_t 
nitems,
   struct headers_check_result *check_res =
     (struct headers_check_result *) userdata;
 
-  if ((MHD_STATICSTR_LEN_ (HEADER1_CRLF) == data_size) &&
-      (0 == memcmp (HEADER1_CRLF, buffer, data_size)))
+  if ((MHD_STATICSTR_LEN_ (RP_HEADER1_CRLF) == data_size) &&
+      (0 == memcmp (RP_HEADER1_CRLF, buffer, data_size)))
     check_res->header1_found++;
-  else if ((MHD_STATICSTR_LEN_ (HEADER2_CRLF) == data_size) &&
-           (0 == memcmp (HEADER2_CRLF, buffer, data_size)))
+  else if ((MHD_STATICSTR_LEN_ (RP_HEADER2_CRLF) == data_size) &&
+           (0 == memcmp (RP_HEADER2_CRLF, buffer, data_size)))
     check_res->header2_found++;
   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ")
             < data_size) &&
@@ -278,22 +445,29 @@ lcurl_hdr_callback (char *buffer, size_t size, size_t 
nitems,
     if ((res <= 0) || (res > ((int) (sizeof(cmpbuf) - 1))))
       externalErrorExit ();
     if (data_size - numbers_pos <= 2)
-      mhdErrorExitDesc ("Broken Content-Length");
+    {
+      fprintf (stderr, "Broken Content-Length.\n");
+      check_res->size_broken_found++;
+    }
     else if ((((size_t) res + 2) != data_size - numbers_pos) ||
              (0 != memcmp (buffer + numbers_pos, cmpbuf, (size_t) res)))
     {
-      fprintf (stderr, "Wrong Content-Length.\n"
-               "Expected:\n%u\n"
-               "Received:\n%s", check_res->expected_size,
+      fprintf (stderr, "Wrong Content-Length. "
+               "Expected: %u. "
+               "Received: %.*s.\n",
+               check_res->expected_size,
+               (int) (data_size - numbers_pos - 2),
                buffer + numbers_pos);
-      mhdErrorExitDesc ("Wrong Content-Length");
+      check_res->size_broken_found++;
     }
     else if (0 != memcmp ("\r\n", buffer + data_size - 2, 2))
     {
-      mhdErrorExitDesc ("The Content-Length header is not " \
-                        "terminated by CRLF");
+      fprintf (stderr, "The Content-Length header is not "
+               "terminated by CRLF.\n");
+      check_res->size_broken_found++;
     }
-    check_res->size_found++;
+    else
+      check_res->size_found++;
   }
 
   return data_size;
@@ -302,9 +476,13 @@ lcurl_hdr_callback (char *buffer, size_t size, size_t 
nitems,
 
 struct CBC
 {
-  char *buf;
-  size_t pos;
-  size_t size;
+  /* Upload members */
+  size_t up_pos;
+  size_t up_size;
+  /* Download members */
+  char *dn_buf;
+  size_t dn_pos;
+  size_t dn_buf_size;
 };
 
 
@@ -314,131 +492,39 @@ copyBuffer (void *ptr,
             size_t nmemb,
             void *ctx)
 {
-  (void) ptr; /* Unused, mute compiler warning */
-  (void) ctx; /* Unused, mute compiler warning */
-  if ((0 != size) && (0 != nmemb))
-    libcurlErrorExitDesc ("Received unexpected body data");
-  return size * nmemb;
-}
+  struct CBC *cbc = ctx;
 
-
-struct ahc_cls_type
-{
-  const char *rq_method;
-  const char *rq_url;
-};
-
-
-static enum MHD_Result
-ahcCheck (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  static int marker;
-  struct MHD_Response *response;
-  enum MHD_Result ret;
-  struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
-  unsigned int http_code;
-
-  if (NULL == param)
-    mhdErrorExitDesc ("cls parameter is NULL");
-
-  if (oneone)
-  {
-    if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
-      mhdErrorExitDesc ("Unexpected HTTP version");
-  }
-  else
-  {
-    if (0 != strcmp (version, MHD_HTTP_VERSION_1_0))
-      mhdErrorExitDesc ("Unexpected HTTP version");
-  }
-
-  if (0 != strcmp (url, param->rq_url))
-    mhdErrorExitDesc ("Unexpected URI");
-
-  if (NULL != upload_data)
-    mhdErrorExitDesc ("'upload_data' is not NULL");
-
-  if (NULL == upload_data_size)
-    mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
-
-  if (0 != *upload_data_size)
-    mhdErrorExitDesc ("'*upload_data_size' value is not zero");
-
-  if (0 != strcmp (param->rq_method, method))
-    mhdErrorExitDesc ("Unexpected request method");
-
-  if (&marker != *req_cls)
-  {
-    *req_cls = &marker;
-    return MHD_YES;
-  }
-  *req_cls = NULL;
-
-  if (0 == strcmp (url, EXISTING_URI))
-  {
-    response =
-      MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
-                                              PAGE);
-    http_code = MHD_HTTP_OK;
-  }
-  else
-  {
-    response =
-      MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE_404),
-                                              PAGE_404);
-    http_code = MHD_HTTP_NOT_FOUND;
-  }
-  if (NULL == response)
-    mhdErrorExitDesc ("Failed to create response");
-
-  if (MHD_YES != MHD_add_response_header (response,
-                                          HEADER1_NAME,
-                                          HEADER1_VALUE))
-    mhdErrorExitDesc ("Cannot add header1");
-  if (MHD_YES != MHD_add_response_header (response,
-                                          HEADER2_NAME,
-                                          HEADER2_VALUE))
-    mhdErrorExitDesc ("Cannot add header2");
-
-  ret = MHD_queue_response (connection,
-                            http_code,
-                            response);
-  MHD_destroy_response (response);
-  if (MHD_YES != ret)
-    mhdErrorExitDesc ("Failed to queue response");
-
-  return ret;
+  if (cbc->dn_pos + size * nmemb > cbc->dn_buf_size)
+    return 0;                   /* overflow */
+  memcpy (&cbc->dn_buf[cbc->dn_pos], ptr, size * nmemb);
+  cbc->dn_pos += size * nmemb;
+  return size * nmemb;
 }
 
 
-/**
- * Set required URI for the request
- * @param c the CURL handle to use
- * @param uri_exist if non-zero use request for "existing" URI
- */
-static void
-setCURL_rq_path (CURL *c, int uri_exist)
+static size_t
+libcurlUploadDataCB (void *stream, size_t item_size, size_t nitems, void *ctx)
 {
-  if (uri_exist)
-  {
-    if (CURLE_OK !=
-        curl_easy_setopt (c, CURLOPT_URL,
-                          URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
-      libcurlErrorExitDesc ("Cannot set request URL");
-  }
-  else
-  {
-    if (CURLE_OK !=
-        curl_easy_setopt (c, CURLOPT_URL,
-                          URL_SCHEME_HOST EXPECTED_URI_BASE_PATH_MISSING))
-      libcurlErrorExitDesc ("Cannot set request URL");
-  }
+  size_t to_fill;
+  struct CBC *cbc = ctx;
+
+  to_fill = cbc->up_size - cbc->up_pos;
+  if (to_fill > item_size * nitems)
+    to_fill = item_size * nitems;
+
+  /* Avoid libcurl magic numbers */
+#ifdef CURL_READFUNC_PAUSE
+  if (CURL_READFUNC_ABORT == to_fill)
+    to_fill -= 2;
+#endif /* CURL_READFUNC_PAUSE */
+#ifdef CURL_READFUNC_ABORT
+  if (CURL_READFUNC_ABORT == to_fill)
+    --to_fill;
+#endif /* CURL_READFUNC_ABORT */
+
+  memcpy (stream, put_data + cbc->up_pos, to_fill);
+  cbc->up_pos += to_fill;
+  return to_fill;
 }
 
 
@@ -524,25 +610,263 @@ setupCURL (void *cbc, uint16_t port,
 #endif /* _DEBUG */
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
                                      &libcurl_debug_cb)) ||
-#if CURL_AT_LEAST_VERSION (7, 85, 0)
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS_STR, "http")) ||
-#elif CURL_AT_LEAST_VERSION (7, 19, 4)
+#if CURL_AT_LEAST_VERSION (7, 19, 4)
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
 #if CURL_AT_LEAST_VERSION (7, 45, 0)
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) ||
 #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL,
+                                     URL_SCHEME_HOST_PATH)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))))
     libcurlErrorExitDesc ("curl_easy_setopt() failed");
 
-  /* When 'CURLOPT_NOBODY' is set, libcurl should use HEAD request. */
-  if (CURLE_OK != curl_easy_setopt (c, CURLOPT_NOBODY, (long) 1))
-    libcurlErrorExitDesc ("curl_easy_setopt() failed");
+  if (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPHEADER, libcurl_headers))
+    libcurlErrorExitDesc ("Failed to set request headers");
+
+  if (use_put)
+  {
+    if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_UPLOAD, 1L)) ||
+        (CURLE_OK != curl_easy_setopt (c, CURLOPT_READFUNCTION,
+                                       libcurlUploadDataCB)) ||
+        (CURLE_OK != curl_easy_setopt (c, CURLOPT_READDATA,
+                                       cbc)))
+      libcurlErrorExitDesc ("Failed to configure the PUT upload");
+  }
 
   return c;
 }
 
 
+struct ahc_cls_type
+{
+  const char *rq_method;
+  const char *rq_url;
+
+  unsigned int num_req;
+  /* Position in the upload data, not compatible with parallel requests */
+  size_t up_pos;
+  size_t expected_upload_size;
+  unsigned int req_check_error;
+};
+
+
+static enum MHD_Result
+ahcCheck (void *cls,
+          struct MHD_Connection *connection,
+          const char *url,
+          const char *method,
+          const char *version,
+          const char *upload_data, size_t *upload_data_size,
+          void **req_cls)
+{
+  static int marker;
+  struct MHD_Response *response;
+  enum MHD_Result ret;
+  struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
+
+  if (NULL == param)
+    mhdErrorExitDesc ("cls parameter is NULL");
+
+  if (oneone)
+  {
+    if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
+      mhdErrorExitDesc ("Unexpected HTTP version");
+  }
+  else
+  {
+    if (0 != strcmp (version, MHD_HTTP_VERSION_1_0))
+      mhdErrorExitDesc ("Unexpected HTTP version");
+  }
+
+  if (0 != strcmp (url, param->rq_url))
+    mhdErrorExitDesc ("Unexpected URI");
+
+  if (0 != strcmp (param->rq_method, method))
+    mhdErrorExitDesc ("Unexpected request method");
+
+  if (NULL == upload_data_size)
+    mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
+
+  if (NULL != upload_data)
+  {
+    size_t report_processed_size;
+    if (0 == *upload_data_size)
+      mhdErrorExitDesc ("'*upload_data_size' value is zero");
+    report_processed_size = *upload_data_size;
+    /* The next checks are not compatible with parallel requests */
+    if (*upload_data_size > param->expected_upload_size - param->up_pos)
+    {
+      fprintf (stderr, "Unexpected *upload_data_size value: %lu. "
+               "Already processed data size: %lu. "
+               "Total expected upload size: %lu. "
+               "Expected unprocessed upload size: %lu. "
+               "The upload data cannot be checked.\n",
+               (unsigned long) *upload_data_size,
+               (unsigned long) param->up_pos,
+               (unsigned long) param->expected_upload_size,
+               (unsigned long) (param->expected_upload_size - param->up_pos));
+      param->req_check_error++;
+    }
+    else
+    {
+      if (0 != memcmp (upload_data, put_data + param->up_pos,
+                       *upload_data_size))
+      {
+        fprintf (stderr, "Wrong upload data.\n"
+                 "Expected: '%.*s'\n"
+                 "Received: '%.*s'.\n",
+                 (int) *upload_data_size, upload_data,
+                 (int) *upload_data_size, put_data + param->up_pos);
+        param->req_check_error++;
+      }
+      if (use_put_large &&
+          (report_processed_size > param->expected_upload_size / 10))
+        report_processed_size = param->expected_upload_size / 10;
+
+      param->up_pos += report_processed_size;
+    }
+    *upload_data_size -= report_processed_size;
+    return MHD_YES;
+  }
+  else
+  {
+    if (0 != *upload_data_size)
+      mhdErrorExitDesc ("'*upload_data_size' value is not zero");
+  }
+
+  if (1)
+  {
+    /* Check headers */
+    const char *value;
+    size_t value_len;
+    unsigned int header_check_error;
+
+    header_check_error = 0;
+
+    value = MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
+                                         RQ_HEADER1_NAME);
+    if (NULL == value)
+    {
+      fprintf (stderr, "Request header '" RQ_HEADER1_NAME "' not found.\n");
+      header_check_error++;
+    }
+    else
+    {
+      if (0 != strcmp (value, RQ_HEADER1_VALUE))
+      {
+        fprintf (stderr, "Wrong header '" RQ_HEADER1_NAME "'value. "
+                 "Expected: '%s'. Received: '%s'.\n",
+                 RQ_HEADER1_VALUE, value);
+        header_check_error++;
+      }
+    }
+
+    if (MHD_YES !=
+        MHD_lookup_connection_value_n (connection, MHD_HEADER_KIND,
+                                       RQ_HEADER2_NAME,
+                                       MHD_STATICSTR_LEN_ (RQ_HEADER2_NAME),
+                                       &value, &value_len))
+    {
+      fprintf (stderr, "Request header '" RQ_HEADER2_NAME "' not found.\n");
+      header_check_error++;
+    }
+    else
+    {
+      if (NULL == value)
+        mhdErrorExitDesc ("The 'value' pointer is NULL");
+      if (strlen (value) != value_len)
+        mhdErrorExitDesc ("The 'value' length does not match strlen(value)");
+
+      if (value_len < MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S)
+          + MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E))
+      {
+        fprintf (stderr, "The value_len is too short. The value: '%s'.\n",
+                 value);
+        header_check_error++;
+      }
+      if (0 != memcmp (value, RQ_HEADER2_VALUE_S,
+                       MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S)))
+      {
+        fprintf (stderr, "The 'value' does not start with '"
+                 RQ_HEADER2_VALUE_S "'. The 'value' is '%s'. ",
+                 value);
+        header_check_error++;
+      }
+      if (0 != memcmp (value
+                       + value_len - MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E),
+                       RQ_HEADER2_VALUE_E,
+                       MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E)))
+      {
+        fprintf (stderr, "The 'value' does not end with '"
+                 RQ_HEADER2_VALUE_E "'. The 'value' is '%s'. ",
+                 value);
+        header_check_error++;
+      }
+    }
+
+    value = MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
+                                         RQ_HEADER3_NAME);
+    if (NULL == value)
+    {
+      fprintf (stderr, "Request header '" RQ_HEADER3_NAME "' not found.\n");
+      header_check_error++;
+    }
+    else
+    {
+      if (0 != strcmp (value, RQ_HEADER3_VALUE))
+      {
+        fprintf (stderr, "Wrong header '" RQ_HEADER3_NAME "'value. "
+                 "Expected: '%s'. Received: '%s'.\n",
+                 RQ_HEADER3_VALUE, value);
+        header_check_error++;
+      }
+    }
+    param->req_check_error += header_check_error;
+  }
+
+  if (&marker != *req_cls)
+  {
+    *req_cls = &marker;
+    if (param->num_req)
+      mhdErrorExitDesc ("Got unexpected second request");
+    param->num_req++;
+    return MHD_YES;
+  }
+  *req_cls = NULL;
+
+  if (0 != strcmp (url, EXPECTED_URI_BASE_PATH))
+  {
+    fprintf (stderr, "Unexpected URI: '%s'. ", url);
+    mhdErrorExitDesc ("Unexpected URI found");
+  }
+
+  response =
+    MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
+                                            PAGE);
+  if (NULL == response)
+    mhdErrorExitDesc ("Failed to create response");
+
+  if (MHD_YES != MHD_add_response_header (response,
+                                          RP_HEADER1_NAME,
+                                          RP_HEADER1_VALUE))
+    mhdErrorExitDesc ("Cannot add header1");
+  if (MHD_YES != MHD_add_response_header (response,
+                                          RP_HEADER2_NAME,
+                                          RP_HEADER2_VALUE))
+    mhdErrorExitDesc ("Cannot add header2");
+
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_OK,
+                            response);
+  MHD_destroy_response (response);
+  if (MHD_YES != ret)
+    mhdErrorExitDesc ("Failed to queue response");
+
+  return ret;
+}
+
+
 static CURLcode
 performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse)
 {
@@ -550,6 +874,7 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
   time_t start;
   struct timeval tv;
   CURLcode ret;
+  int libcurl_finished;
 
   ret = CURLE_FAILED_INIT; /* will be replaced with real result */
   if (NULL != *multi_reuse)
@@ -563,6 +888,7 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
   }
   if (CURLM_OK != curl_multi_add_handle (multi, c))
     libcurlErrorExitDesc ("curl_multi_add_handle() failed");
+  libcurl_finished = 0;
 
   start = time (NULL);
   while (time (NULL) - start <= TIMEOUTS_VAL)
@@ -572,15 +898,15 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, 
CURLM **multi_reuse)
     fd_set es;
     MHD_socket maxMhdSk;
     int maxCurlSk;
-    int running;
 
     maxMhdSk = MHD_INVALID_SOCKET;
     maxCurlSk = -1;
     FD_ZERO (&rs);
     FD_ZERO (&ws);
     FD_ZERO (&es);
-    if (NULL != multi)
+    if (! libcurl_finished)
     {
+      int running;
       curl_multi_perform (multi, &running);
       if (0 == running)
       {
@@ -605,7 +931,7 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
           externalErrorExit ();
         }
         curl_multi_remove_handle (multi, c);
-        multi = NULL;
+        libcurl_finished = ! 0;
       }
       else
       {
@@ -613,7 +939,7 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
           libcurlErrorExitDesc ("curl_multi_fdset() failed");
       }
     }
-    if (NULL == multi)
+    if (libcurl_finished)
     { /* libcurl has finished, check whether MHD still needs to perform 
cleanup */
       if (0 != MHD_get_timeout64s (d))
         break; /* MHD finished as well */
@@ -663,11 +989,14 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, 
CURLM **multi_reuse)
  */
 static unsigned int
 check_result (CURLcode curl_code, CURL *c, long expected_code,
-              struct headers_check_result *hdr_res)
+              struct CBC *pcbc, struct headers_check_result *hdr_res,
+              struct ahc_cls_type *ahc_cls)
 {
   long code;
   unsigned int ret;
 
+  fflush (stderr);
+  fflush (stdout);
   if (CURLE_OK != curl_code)
   {
     fflush (stdout);
@@ -681,7 +1010,6 @@ check_result (CURLcode curl_code, CURL *c, long 
expected_code,
       fprintf (stderr, "Request failed. "
                "libcurl error: '%s'.\n",
                curl_easy_strerror (curl_code));
-    fflush (stderr);
     return 0;
   }
 
@@ -698,6 +1026,23 @@ check_result (CURLcode curl_code, CURL *c, long 
expected_code,
     printf ("The response has expected HTTP code: %ld\n", expected_code);
 
   ret = 1;
+
+  if (ahc_cls->req_check_error)
+  {
+    fprintf (stderr, "One or more errors have been detected by access "
+             "handler callback.\n");
+    ret = 0;
+  }
+  if (ahc_cls->expected_upload_size != ahc_cls->up_pos)
+  {
+    fprintf (stderr, "Upload size does not match expected. "
+             "Expected: %lu. "
+             "Received: %lu.\n",
+             (unsigned long) ahc_cls->expected_upload_size,
+             (unsigned long) ahc_cls->up_pos);
+    ret = 0;
+  }
+
   if (1 != hdr_res->header1_found)
   {
     if (0 == hdr_res->header1_found)
@@ -723,22 +1068,45 @@ check_result (CURLcode curl_code, CURL *c, long 
expected_code,
   if (1 != hdr_res->size_found)
   {
     if (0 == hdr_res->size_found)
-      fprintf (stderr, "Response 'Content-Length' header was not found.\n");
+      fprintf (stderr, "Correct response 'Content-Length' header "
+               "was not found.\n");
     else
-      fprintf (stderr, "Response 'Content-Length' header was found %d times "
-               "instead of one time only.\n", hdr_res->size_found);
+      fprintf (stderr, "Correct response 'Content-Length' header "
+               "was found %u times instead of one time only.\n",
+               hdr_res->size_found);
     ret = 0;
   }
   else if (verbose)
     printf ("'Content-Length' header with correct value "
             "is present in the response.\n");
+  if (0 != hdr_res->size_broken_found)
+  {
+    fprintf (stderr, "Wrong response 'Content-Length' header was found "
+             "%u times.\n", hdr_res->size_broken_found);
+    ret = 0;
+  }
 
+  if (pcbc->dn_pos != MHD_STATICSTR_LEN_ (PAGE))
+  {
+    fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ",
+             (unsigned) pcbc->dn_pos, (int) pcbc->dn_pos, pcbc->dn_buf,
+             (unsigned) MHD_STATICSTR_LEN_ (PAGE));
+    mhdErrorExitDesc ("Wrong returned data length");
+  }
+  if (0 != memcmp (PAGE, pcbc->dn_buf, pcbc->dn_pos))
+  {
+    fprintf (stderr, "Got invalid response '%.*s'. ",
+             (int) pcbc->dn_pos, pcbc->dn_buf);
+    mhdErrorExitDesc ("Wrong returned data");
+  }
+  fflush (stderr);
+  fflush (stdout);
   return ret;
 }
 
 
 static unsigned int
-testHead (void)
+performCheck (void)
 {
   struct MHD_Daemon *d;
   uint16_t port;
@@ -753,12 +1121,35 @@ testHead (void)
   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
     port = 0;
   else
-    port = 4220 + oneone ? 0 : 1;
+  {
+    port =  UINT16_C (4220);
+    if (! oneone)
+      port += UINT16_C (1);
+    if (use_put)
+      port += UINT16_C (2);
+    if (use_put_large)
+      port += UINT16_C (4);
+    if (use_hdr_last)
+      port += UINT16_C (8);
+    if (use_hdr_large)
+      port += UINT16_C (16);
+  }
 
-  d = MHD_start_daemon (MHD_USE_ERROR_LOG,
-                        port, NULL, NULL,
-                        &ahcCheck, &ahc_param,
-                        MHD_OPTION_END);
+  if (1)
+  {
+    size_t mem_limit;
+    if (use_put_large)
+      mem_limit = (size_t) (TEST_UPLOAD_DATA_SIZE / 2 + HEADERS_POINTERS_SIZE);
+    else
+      mem_limit = (size_t) ((TEST_UPLOAD_DATA_SIZE * 4) / 3 + 2 +
+                            HEADERS_POINTERS_SIZE);
+
+    d = MHD_start_daemon (MHD_USE_ERROR_LOG,
+                          port, NULL, NULL,
+                          &ahcCheck, &ahc_param,
+                          MHD_OPTION_CONNECTION_MEMORY_LIMIT, mem_limit,
+                          MHD_OPTION_END);
+  }
   if (d == NULL)
     return 1;
   if (0 == port)
@@ -774,22 +1165,28 @@ testHead (void)
   }
 
   /* First request */
-  ahc_param.rq_method = MHD_HTTP_METHOD_HEAD;
+  ahc_param.rq_method = use_put ? MHD_HTTP_METHOD_PUT : MHD_HTTP_METHOD_GET;
   ahc_param.rq_url = EXPECTED_URI_BASE_PATH;
+  ahc_param.expected_upload_size = use_put ? TEST_UPLOAD_DATA_SIZE : 0;
+  ahc_param.req_check_error = 0;
+  ahc_param.num_req = 0;
+  ahc_param.up_pos = 0;
   rp_headers_check.expected_size = MHD_STATICSTR_LEN_ (PAGE);
   rp_headers_check.header1_found = 0;
   rp_headers_check.header2_found = 0;
   rp_headers_check.size_found = 0;
-  cbc.buf = buf;
-  cbc.size = sizeof (buf);
-  cbc.pos = 0;
-  memset (cbc.buf, 0, cbc.size);
+  rp_headers_check.size_broken_found = 0;
+  cbc.dn_buf = buf;
+  cbc.dn_buf_size = sizeof (buf);
+  cbc.dn_pos = 0;
+  memset (cbc.dn_buf, 0, cbc.dn_buf_size);
+  cbc.up_size = TEST_UPLOAD_DATA_SIZE;
+  cbc.up_pos = 0;
   c = setupCURL (&cbc, port, &rp_headers_check);
-  setCURL_rq_path (c, 1);
   multi_reuse = NULL;
   /* First request */
   if (check_result (performQueryExternal (d, c, &multi_reuse), c,
-                    MHD_HTTP_OK, &rp_headers_check))
+                    MHD_HTTP_OK, &cbc, &rp_headers_check, &ahc_param))
   {
     fflush (stderr);
     if (verbose)
@@ -803,15 +1200,19 @@ testHead (void)
     failed = 1;
   }
   /* Second request */
-  rp_headers_check.expected_size = MHD_STATICSTR_LEN_ (PAGE_404);
+  ahc_param.req_check_error = 0;
+  ahc_param.num_req = 0;
+  ahc_param.up_pos = 0;
   rp_headers_check.header1_found = 0;
   rp_headers_check.header2_found = 0;
   rp_headers_check.size_found = 0;
-  cbc.pos = 0; /* Reset buffer position */
-  ahc_param.rq_url = EXPECTED_URI_BASE_PATH_MISSING;
-  setCURL_rq_path (c, 0);
+  rp_headers_check.size_broken_found = 0;
+  /* Reset buffer position */
+  cbc.dn_pos = 0;
+  memset (cbc.dn_buf, 0, cbc.dn_buf_size);
+  cbc.up_pos = 0;
   if (check_result (performQueryExternal (d, c, &multi_reuse), c,
-                    MHD_HTTP_NOT_FOUND, &rp_headers_check))
+                    MHD_HTTP_OK, &cbc, &rp_headers_check, &ahc_param))
   {
     fflush (stderr);
     if (verbose)
@@ -825,15 +1226,22 @@ testHead (void)
     failed = 1;
   }
   /* Third request */
+  ahc_param.req_check_error = 0;
+  ahc_param.num_req = 0;
+  ahc_param.up_pos = 0;
   rp_headers_check.header1_found = 0;
   rp_headers_check.header2_found = 0;
   rp_headers_check.size_found = 0;
-  cbc.pos = 0; /* Reset buffer position */
+  rp_headers_check.size_broken_found = 0;
+  /* Reset buffer position */
+  cbc.dn_pos = 0;
+  memset (cbc.dn_buf, 0, cbc.dn_buf_size);
+  cbc.up_pos = 0;
   if (NULL != multi_reuse)
     curl_multi_cleanup (multi_reuse);
   multi_reuse = NULL; /* Force new connection */
   if (check_result (performQueryExternal (d, c, &multi_reuse), c,
-                    MHD_HTTP_NOT_FOUND, &rp_headers_check))
+                    MHD_HTTP_OK, &cbc, &rp_headers_check, &ahc_param))
   {
     fflush (stderr);
     if (verbose)
@@ -868,9 +1276,25 @@ main (int argc, char *const *argv)
                has_param (argc, argv, "--silent"));
   oneone = ! has_in_name (argv[0], "10");
 
+  use_get = has_in_name (argv[0], "_get");
+  use_put = has_in_name (argv[0], "_put");
+
+  use_double_fold = has_in_name (argv[0], "_double_fold");
+  use_put_large = has_in_name (argv[0], "_put_large");
+  use_hdr_last = has_in_name (argv[0], "_last");
+  use_hdr_large = has_in_name (argv[0], "_fold_large");
+
+  if (1 !=
+      ((use_get ? 1 : 0) + (use_put ? 1 : 0)))
+  {
+    fprintf (stderr, "Wrong test name '%s': no or multiple indications "
+             "for the test type.\n", argv[0] ? argv[0] : "(NULL)");
+    return 99;
+  }
+
   test_global_init ();
 
-  errorCount += testHead ();
+  errorCount += performCheck ();
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
   test_global_cleanup ();
diff --git a/src/testzzuf/Makefile.am b/src/testzzuf/Makefile.am
index 69c6df87..f38c6d0e 100644
--- a/src/testzzuf/Makefile.am
+++ b/src/testzzuf/Makefile.am
@@ -1,16 +1,40 @@
 # This Makefile.am is in the public domain
+
 SUBDIRS  = .
 
+# ZZUF_SEED can be redefined to use other initial seeds
+# for extended testing. E.g.,
+#  make ZZUF_SEED=1234 check
+ZZUF_SEED = 0
+
+# Additional flags for zzuf
+ZZUF_FLAGS = 
+
+# Additional flags for socat (if socat is used)
+SOCAT_FLAGS = 
+
+if FORCE_USE_ZZUF_SOCAT
+TEST_RUNNER_SCRIPT = zzuf_socat_test_runner.sh
+else
+TEST_RUNNER_SCRIPT = zzuf_test_runner.sh
+endif
+
 AM_CPPFLAGS = \
   -I$(top_srcdir)/src/include \
+  -I$(top_srcdir)/src/microhttpd \
   -DMHD_CPU_COUNT=$(CPU_COUNT) \
   $(CPPFLAGS_ac) $(LIBCURL_CPPFLAGS)
 
-AM_CFLAGS = $(CFLAGS_ac) @LIBGCRYPT_CFLAGS@
+AM_CFLAGS = $(CFLAGS_ac)
 
 AM_LDFLAGS = $(LDFLAGS_ac)
 
-AM_TESTS_ENVIRONMENT = $(TESTS_ENVIRONMENT_ac)
+AM_TESTS_ENVIRONMENT = $(TESTS_ENVIRONMENT_ac) \
+  ZZUF="$(ZZUF)" ; export ZZUF ; \
+  ZZUF_SEED="$(ZZUF_SEED)" ; export ZZUF_SEED ; \
+  ZZUF_FLAGS="$(ZZUF_FLAGS)" ; export ZZUF_FLAGS ; \
+  SOCAT="$(SOCAT)" ; export SOCAT ; \
+  SOCAT_FLAGS="$(SOCAT_FLAGS)" ; export SOCAT_FLAGS ;
 
 if USE_COVERAGE
   AM_CFLAGS += -fprofile-arcs -ftest-coverage
@@ -24,11 +48,6 @@ $(top_builddir)/src/microhttpd/libmicrohttpd.la: 
$(top_builddir)/src/microhttpd/
        @echo ' cd $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) 
libmicrohttpd.la'; \
        $(am__cd) $(top_builddir)/src/microhttpd && $(MAKE) $(AM_MAKEFLAGS) 
libmicrohttpd.la
 
-EXTRA_DIST = README socat.c
-
-THREAD_ONLY_TESTS = \
-  test_long_header
-
 check_PROGRAMS = \
   test_get \
   test_get_chunked \
@@ -37,64 +56,98 @@ check_PROGRAMS = \
   test_put \
   test_put_chunked \
   test_put_large \
-  test_get11 \
-  test_post11 \
-  test_post_form11 \
-  test_put11 \
-  test_put_large11
+  test_get_long_uri \
+  test_get_long_header \
+  test_get_close \
+  test_get_chunked_close \
+  test_post_close \
+  test_post_form_close \
+  test_put_close \
+  test_put_chunked_close \
+  test_put_large_close \
+  test_get_long_uri_close \
+  test_get_long_header_close \
+  test_get10 \
+  test_get_chunked10 \
+  test_post10 \
+  test_post_form10 \
+  test_put10 \
+  test_put_large10 \
+  test_get_long_uri10 \
+  test_get_long_header10
 
 .NOTPARALLEL:
 
 
-if USE_POSIX_THREADS
-check_PROGRAMS += \
-  $(THREAD_ONLY_TESTS)
-endif
-if USE_W32_THREADS
-check_PROGRAMS += \
-  $(THREAD_ONLY_TESTS)
+TESTS = $(check_PROGRAMS)
+
+dist_check_SCRIPTS = zzuf_test_runner.sh zzuf_socat_test_runner.sh
+
+LOG_COMPILER = @SHELL@ "$(srcdir)/$(TEST_RUNNER_SCRIPT)"
+
+if VHEAVY_TESTS
+check_SCRIPTS = warn_vheavy_use
+
+.PHONY: warn_vheavy_use
 endif
 
+warn_vheavy_use:
+       @echo "NOTICE" ; \
+       echo "NOTICE: Full heavy tests are enabled. Each test may take up to 
several minutes to complete." ; \
+       echo "NOTICE"
+       
 
-TESTS = $(check_PROGRAMS)
+tests_common_sources = mhd_debug_funcs.h mhd_debug_funcs.c 
 
 test_get_SOURCES = \
-  test_get.c
+  test_get.c $(tests_common_sources)
+
+test_get_chunked_SOURCES = $(test_get_SOURCES)
+
+test_post_SOURCES = $(test_get_SOURCES)
+
+test_post_form_SOURCES = $(test_get_SOURCES)
+
+test_put_SOURCES = $(test_get_SOURCES)
+
+test_put_chunked_SOURCES = $(test_get_SOURCES)
+
+test_put_large_SOURCES = $(test_get_SOURCES)
+
+test_get_long_uri_SOURCES = $(test_get_SOURCES)
+
+test_get_long_header_SOURCES = $(test_get_SOURCES)
+
+test_get_close_SOURCES = $(test_get_SOURCES)
+
+test_get_chunked_close_SOURCES = $(test_get_chunked_SOURCES)
+
+test_post_close_SOURCES = $(test_post_SOURCES)
 
-test_get_chunked_SOURCES = \
-  test_get_chunked.c
+test_post_form_close_SOURCES = $(test_post_form_SOURCES)
 
-test_post_SOURCES = \
-  test_post.c
+test_put_close_SOURCES = $(test_put_SOURCES)
 
-test_post_form_SOURCES = \
-  test_post_form.c
+test_put_chunked_close_SOURCES = $(test_put_chunked_SOURCES)
 
-test_put_SOURCES = \
-  test_put.c
+test_put_large_close_SOURCES = $(test_put_large_SOURCES)
 
-test_put_chunked_SOURCES = \
-  test_put_chunked.c
+test_get_long_uri_close_SOURCES = $(test_get_long_uri_SOURCES)
 
-test_put_large_SOURCES = \
-  test_put_large.c
+test_get_long_header_close_SOURCES = $(test_get_long_header_SOURCES)
 
+test_get10_SOURCES = $(test_get_SOURCES)
 
+test_get_chunked10_SOURCES = $(test_get_chunked_SOURCES)
 
-test_get11_SOURCES = \
-  test_get.c
+test_post10_SOURCES = $(test_post_SOURCES)
 
-test_post11_SOURCES = \
-  test_post.c
+test_post_form10_SOURCES = $(test_post_form_SOURCES)
 
-test_post_form11_SOURCES = \
-  test_post_form.c
+test_put10_SOURCES = $(test_put_SOURCES)
 
-test_put11_SOURCES = \
-  test_put.c
+test_put_large10_SOURCES = $(test_put_large_SOURCES)
 
-test_put_large11_SOURCES = \
-  test_put_large.c
+test_get_long_uri10_SOURCES = $(test_get_long_uri_SOURCES)
 
-test_long_header_SOURCES = \
-  test_long_header.c
+test_get_long_header10_SOURCES = $(test_get_long_header_SOURCES)
diff --git a/src/testzzuf/mhd_debug_funcs.c b/src/testzzuf/mhd_debug_funcs.c
new file mode 100644
index 00000000..5db50b41
--- /dev/null
+++ b/src/testzzuf/mhd_debug_funcs.c
@@ -0,0 +1,108 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 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.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file testzzuf/mhd_debug_funcs.c
+ * @brief  Implementations of MHD private debug functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_debug_funcs.h"
+#include "internal.h"
+#include "mhd_sockets.h"
+
+/**
+ * Checks whether MHD can use accept() syscall and
+ * avoid accept4() syscall.
+ * @return non-zero if accept() is possible,
+ *         zero if accept4() is always used by MHD
+ */
+int
+MHD_is_avoid_accept4_possible_ (void)
+{
+#if ! defined(USE_ACCEPT4)
+  return ! 0;
+#else  /* ! USE_ACCEPT4 */
+  return (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_DEBUG_BUILD)) ?
+         ! 0 : 0;
+#endif /* ! USE_ACCEPT4 */
+}
+
+
+/**
+ * Switch MHD daemon to use accept() syscalls for new connections.
+ * @param daemon the daemon to operate
+ */
+void
+MHD_avoid_accept4_ (struct MHD_Daemon *daemon)
+{
+  (void) daemon; /* Mute compiler warning */
+#ifdef USE_ACCEPT4
+#ifdef _DEBUG
+  daemon->avoid_accept4 = true;
+#else  /* ! _DEBUG */
+  abort ();
+#endif /* ! _DEBUG */
+#endif /* USE_ACCEPT4 */
+}
+
+#ifdef MHD_ASAN_ACTIVE
+#define MHD_ASAN_ENABLED_ 1
+#else  /* ! MHD_ASAN_ACTIVE */
+#ifdef __SANITIZE_ADDRESS__
+#define MHD_ASAN_ENABLED_ 1
+#else  /* ! __SANITIZE_ADDRESS__ */
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define MHD_ASAN_ENABLED_ 1
+#endif /* __has_feature(address_sanitizer) */
+#endif /* __has_feature */
+#endif /* ! __SANITIZE_ADDRESS__ */
+#endif /* ! MHD_ASAN_ACTIVE */
+/**
+ * Checks whether any know sanitizer is enabled for this build.
+ * zzuf does not work together with sanitizers as both are intercepting
+ * standard library calls.
+ * @return non-zero if any sanitizer is enabled,
+ *         zero otherwise
+ */
+int
+MHD_are_sanitizers_enabled_ (void)
+{
+  int ret = 0;
+#ifdef MHD_ASAN_ENABLED_
+  ++ret;
+#endif /* ! MHD_ASAN_ENABLED_ */
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+  ++ret;
+#endif
+#if __has_feature(memory_sanitizer)
+  ++ret;
+#endif
+#if __has_feature(dataflow_sanitizer)
+  ++ret;
+#endif
+#else  /* ! defined(__has_feature) */
+#ifdef __SANITIZE_THREAD__
+  ++ret;
+#endif
+#endif /* ! defined(__has_feature) */
+  return ret;
+}
diff --git a/src/testzzuf/mhd_debug_funcs.h b/src/testzzuf/mhd_debug_funcs.h
new file mode 100644
index 00000000..04de0970
--- /dev/null
+++ b/src/testzzuf/mhd_debug_funcs.h
@@ -0,0 +1,57 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 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.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file testzzuf/mhd_debug_funcs.h
+ * @brief  Declarations of MHD private debug functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_DEBUG_FUNCS_H
+#define MHD_DEBUG_FUNCS_H 1
+
+struct MHD_Daemon;
+
+/**
+ * Checks whether MHD can use accept() syscall and
+ * avoid accept4() syscall.
+ * @return non-zero if accept() is possible,
+ *         zero if accept4() is always used by MHD
+ */
+int
+MHD_is_avoid_accept4_possible_ (void);
+
+/**
+ * Switch MHD daemon to use accept() syscalls for new connections.
+ * @param daemon the daemon to operate
+ */
+void
+MHD_avoid_accept4_ (struct MHD_Daemon *daemon);
+
+/**
+ * Checks whether any know sanitizer is enabled for this build.
+ * zzuf does not work together with sanitizers as both are intercepting
+ * standard library calls.
+ * @return non-zero if any sanitizer is enabled,
+ *         zero otherwise
+ */
+int
+MHD_are_sanitizers_enabled_ (void);
+
+#endif /* MHD_DEBUG_FUNCS_H */
diff --git a/src/testzzuf/socat.c b/src/testzzuf/socat.c
deleted file mode 100644
index 0ee14749..00000000
--- a/src/testzzuf/socat.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2008,2016 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file socat.c
- * @brief  Code to fork-exec zzuf and start the socat process
- * @author Christian Grothoff
- */
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-#ifdef _WIN32
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN 1
-#endif /* !WIN32_LEAN_AND_MEAN */
-#include <windows.h>
-#endif
-
-
-/**
- * A larger loop count will run more random tests --
- * which would be good, except that it may take too
- * long for most user's patience.  So this small
- * value is the default.
- */
-#ifndef _MHD_VHEAVY_TESTS
-#define LOOP_COUNT 10
-#else  /* ! _MHD_VHEAVY_TESTS */
-#define LOOP_COUNT 200
-#endif /* ! _MHD_VHEAVY_TESTS */
-
-#define CURL_TIMEOUT 50L
-
-static pid_t zzuf_pid;
-
-static void
-zzuf_socat_start ()
-{
-  int status;
-  char *const args[] = {
-    "zzuf",
-    "--ratio=0.0:0.75",
-    "-n",
-    "-A",
-    "socat",
-    "-lf",
-    "/dev/null",
-    "TCP4-LISTEN:11081,reuseaddr,fork",
-    "TCP4:127.0.0.1:11080",
-    NULL,
-  };
-  zzuf_pid = fork ();
-  if (zzuf_pid == -1)
-  {
-    fprintf (stderr, "fork failed: %s\n", strerror (errno));
-    exit (1);
-  }
-  if (zzuf_pid != 0)
-  {
-    (void) sleep (1);                 /* allow zzuf and socat to start */
-    status = 0;
-    if (0 < waitpid (zzuf_pid, &status, WNOHANG))
-    {
-      if (WIFEXITED (status))
-        fprintf (stderr,
-                 "zzuf died with status code %d!\n",
-                 WEXITSTATUS (status));
-      if (WIFSIGNALED (status))
-        fprintf (stderr,
-                 "zzuf died from signal %d!\n", WTERMSIG (status));
-      exit (1);
-    }
-    return;
-  }
-  setpgid (0, 0);
-  execvp ("zzuf", args);
-  fprintf (stderr, "execution of `zzuf' failed: %s\n", strerror (errno));
-  exit (1);
-}
-
-
-static void
-zzuf_socat_stop ()
-{
-  int status;
-  if (zzuf_pid != 0)
-  {
-    if (0 != killpg (zzuf_pid, SIGINT))
-      fprintf (stderr, "Failed to killpg: %s\n", strerror (errno));
-    kill (zzuf_pid, SIGINT);
-    waitpid (zzuf_pid, &status, 0);
-    (void) sleep (1);                 /* allow socat to also die in peace */
-  }
-}
-
-
-/* end of socat.c */
diff --git a/src/testzzuf/test_get.c b/src/testzzuf/test_get.c
index e2b86ffe..94a4e833 100644
--- a/src/testzzuf/test_get.c
+++ b/src/testzzuf/test_get.c
@@ -1,6 +1,7 @@
 /*
      This file is part of libmicrohttpd
      Copyright (C) 2007, 2008 Christian Grothoff
+     Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
 
      libmicrohttpd is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -19,12 +20,12 @@
 */
 
 /**
- * @file test_get.c
- * @brief  Testcase for libmicrohttpd GET operations
+ * @file testzzuf/test_get.c
+ * @brief  Several testcases for libmicrohttpd with input fuzzing
  * @author Christian Grothoff
+ * @author Karlson2k (Evgeny Grin)
  */
 
-#include "MHD_config.h"
 #include "platform.h"
 #include <curl/curl.h>
 #include <microhttpd.h>
@@ -36,298 +37,1626 @@
 #include <unistd.h>
 #endif
 
-#include "socat.c"
+#include "mhd_debug_funcs.h"
+#include "test_helpers.h"
 
+#ifndef MHD_STATICSTR_LEN_
+/**
+ * Determine length of static string / macro strings at compile time.
+ */
+#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
+#endif /* ! MHD_STATICSTR_LEN_ */
+
+#ifndef CURL_VERSION_BITS
+#define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z))
+#endif /* ! CURL_VERSION_BITS */
+#ifndef CURL_AT_LEAST_VERSION
+#define CURL_AT_LEAST_VERSION(x,y,z) \
+  (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z))
+#endif /* ! CURL_AT_LEAST_VERSION */
+
+/**
+ * A larger loop count will run more random tests --
+ * which would be good, except that it may take too
+ * long for most user's patience.  So this small
+ * value is the default.
+ * Can be redefined by CPPFLAGS=-DLOOP_COUNT=123
+ */
+#ifndef LOOP_COUNT
+#ifndef _MHD_VHEAVY_TESTS
+#define LOOP_COUNT 10
+#else  /* ! _MHD_HEAVY_TESTS */
+#define LOOP_COUNT 200
+#endif /* ! _MHD_HEAVY_TESTS */
+#endif /* LOOP_COUNT */
+
+#ifdef _DEBUG
+/* Uncomment the next line (or use CPPFLAGS) to see all request and response 
bodies in log */
+/* #define TEST_PRINT_BODY */
+/* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they 
are sent by libcurl */
+/* #define TEST_PRINT_BODY_RQ 1 */
+/* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they 
are received by libcurl */
+/* #define TEST_PRINT_BODY_RP 1 */
+#endif /* _DEBUG */
+
+#define MHD_TIMEOUT 2
+
+#define CURL_TIMEOUT 5
+
+/* Global test parameters */
 static int oneone;
+static int dry_run;
+static int use_get;
+static int use_get_chunked;
+static int use_put;
+static int use_put_large;
+static int use_put_chunked;
+static int use_post;
+static int use_post_form;
+static int use_long_header;
+static int use_long_uri;
+static int use_close;
+static int run_with_socat;
 
-struct CBC
+#define TEST_BASE_URI "http:/" "/127.0.0.1/test_uri"
+#define TEST_BASE_URI_SOCAT "http:/" "/127.0.0.121/test_uri"
+
+#define SOCAT_PORT 10121
+
+#define TEST_BASE_PORT 4010
+
+#define EMPTY_PAGE "Empty page."
+#define EMPTY_PAGE_ALT "Alternative empty page."
+#define METHOD_NOT_SUPPORTED "HTTP method is not supported."
+#define POST_DATA_BROKEN "The POST request is ill-formed."
+
+#define POST_KEY1 "test"
+#define POST_VALUE1 "test_post"
+#define POST_KEY2 "library"
+#define POST_VALUE2 "GNU libmicrohttpd"
+#define POST_URLENC_DATA \
+  POST_KEY1 "=" POST_VALUE1 "&" POST_KEY2 "=" "GNU%20libmicrohttpd"
+
+#define PUT_NORMAL_SIZE 11
+/* Does not need to be very large as MHD buffer will be made smaller anyway */
+#define PUT_LARGE_SIZE (4 * 1024)
+/* The length of "very long" URI and header strings. MHD uses smaller buffer. 
*/
+#define TEST_STRING_VLONG_LEN 8 * 1024
+
+
+#if ! CURL_AT_LEAST_VERSION (7,56,0)
+#define TEST_USE_STATIC_POST_DATA 1
+static struct curl_httppost *post_first;
+static struct curl_httppost *post_last;
+#endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */
+
+static struct curl_slist *libcurl_long_header;
+
+/**
+ * Initialise long header for libcurl
+ *
+ * @return non-zero if succeed,
+ *         zero if failed
+ */
+static int
+long_header_init (void)
 {
   char *buf;
-  size_t pos;
-  size_t size;
+
+  buf = malloc (TEST_STRING_VLONG_LEN + 1);
+  if (NULL == buf)
+  {
+    fprintf (stderr, "malloc() failed "
+             "at line %d.\n", (int) __LINE__);
+    return 0;
+  }
+  buf[TEST_STRING_VLONG_LEN] = 0;
+  buf[0] = 'A';
+  memset (buf + 1, 'a', TEST_STRING_VLONG_LEN / 2 - 2);
+  buf[TEST_STRING_VLONG_LEN / 2 - 1] = ':';
+  buf[TEST_STRING_VLONG_LEN / 2] = ' ';
+  memset (buf + TEST_STRING_VLONG_LEN / 2 + 1, 'c',
+          TEST_STRING_VLONG_LEN / 2 - 1);
+  libcurl_long_header = curl_slist_append (NULL, buf);
+  free (buf);
+  if (NULL != libcurl_long_header)
+    return ! 0; /* Success exit point */
+
+  fprintf (stderr, "curl_slist_append() failed "
+           "at line %d.\n", (int) __LINE__);
+  return 0; /* Failure exit point */
+}
+
+
+/**
+ * Globally initialise test environment
+ * @return non-zero if succeed,
+ *         zero if failed
+ */
+static int
+test_global_init (void)
+{
+  libcurl_long_header = NULL;
+  if (CURLE_OK != curl_global_init (CURL_GLOBAL_WIN32))
+  {
+    fprintf (stderr, "curl_global_init() failed "
+             "at line %d.\n", (int) __LINE__);
+    return 0;
+  }
+
+  if (long_header_init ())
+  {
+#ifndef TEST_USE_STATIC_POST_DATA
+    return 1; /* Success exit point */
+#else  /* ! TEST_USE_STATIC_POST_DATA */
+    post_first = NULL;
+    post_last = NULL;
+    if ((CURL_FORMADD_OK !=
+         curl_formadd (&post_first, &post_last,
+                       CURLFORM_PTRNAME, POST_KEY1,
+                       CURLFORM_NAMELENGTH,
+                       (long) MHD_STATICSTR_LEN_ (POST_KEY1),
+                       CURLFORM_PTRCONTENTS, POST_VALUE1,
+#if CURL_AT_LEAST_VERSION (7,46,0)
+                       CURLFORM_CONTENTLEN,
+                       (curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE1),
+#else  /* ! CURL_AT_LEAST_VERSION(7,46,0) */
+                       CURLFORM_CONTENTSLENGTH,
+                       (long) MHD_STATICSTR_LEN_ (POST_VALUE1),
+#endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */
+                       CURLFORM_END)) ||
+        (CURL_FORMADD_OK !=
+         curl_formadd (&post_first, &post_last,
+                       CURLFORM_PTRNAME, POST_KEY2,
+                       CURLFORM_NAMELENGTH,
+                       (long) MHD_STATICSTR_LEN_ (POST_KEY2),
+                       CURLFORM_PTRCONTENTS, POST_VALUE2,
+#if CURL_AT_LEAST_VERSION (7,46,0)
+                       CURLFORM_CONTENTLEN,
+                       (curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE2),
+#else  /* ! CURL_AT_LEAST_VERSION(7,46,0) */
+                       CURLFORM_CONTENTSLENGTH,
+                       (long) MHD_STATICSTR_LEN_ (POST_VALUE2),
+#endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */
+                       CURLFORM_END)))
+      fprintf (stderr, "curl_formadd() failed "
+               "at line %d.\n", (int) __LINE__);
+    else
+      return 1; /* Success exit point */
+
+    if (NULL != post_first)
+      curl_formfree (post_first);
+    curl_slist_free_all (libcurl_long_header);
+#endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */
+  }
+  curl_global_cleanup ();
+  return 0; /* Failure exit point */
+}
+
+
+/**
+ * Globally de-initialise test environment
+ */
+static void
+test_global_deinit (void)
+{
+#ifdef TEST_USE_STATIC_POST_DATA
+  curl_formfree (post_first);
+#endif /* TEST_USE_STATIC_POST_DATA */
+  curl_global_cleanup ();
+  if (NULL != libcurl_long_header)
+    curl_slist_free_all (libcurl_long_header);
+}
+
+
+/**
+ * libcurl callback parameters for uploads, downloads and debug callbacks
+ */
+struct CBC
+{
+  /* Upload members */
+  size_t up_pos;
+  size_t up_size;
+  /* Download members */
+  char *dn_buf;
+  size_t dn_pos;
+  size_t dn_buf_size;
+  /* Debug callback members */
+  unsigned int excess_found;
 };
 
+static void
+initCBC (struct CBC *libcurlcbc, char *dn_buf, size_t dn_buf_size)
+{
+  libcurlcbc->up_pos = 0;
+  if (use_put_large)
+    libcurlcbc->up_size = PUT_LARGE_SIZE;
+  else if (use_put)
+    libcurlcbc->up_size = PUT_NORMAL_SIZE;
+  else
+    libcurlcbc->up_size = 0;
+  libcurlcbc->dn_buf = dn_buf;
+  libcurlcbc->dn_pos = 0;
+  libcurlcbc->dn_buf_size = dn_buf_size;
+  libcurlcbc->excess_found = 0;
+}
+
+
+static void
+resetCBC (struct CBC *libcurlcbc)
+{
+  libcurlcbc->up_pos = 0;
+  libcurlcbc->dn_pos = 0;
+}
+
+
+static size_t
+putBuffer (void *stream, size_t item_size, size_t nitems, void *ctx)
+{
+  size_t to_fill;
+  size_t i;
+  struct CBC *cbc = ctx;
+
+  to_fill = cbc->up_size - cbc->up_pos;
+  /* Skip overflow check as the return value is valid anyway */
+  if (use_put_chunked)
+  {
+    /* Send data as several chunks */
+    if (to_fill > cbc->up_size / 3)
+      to_fill = cbc->up_size / 3;
+  }
+  if (to_fill > item_size * nitems)
+    to_fill = item_size * nitems;
+
+  /* Avoid libcurl magic numbers */
+#ifdef CURL_READFUNC_PAUSE
+  if (CURL_READFUNC_ABORT == to_fill)
+    to_fill -= 2;
+#endif /* CURL_READFUNC_PAUSE */
+#ifdef CURL_READFUNC_ABORT
+  if (CURL_READFUNC_ABORT == to_fill)
+    --to_fill;
+#endif /* CURL_READFUNC_ABORT */
+  for (i = 0; i < to_fill; ++i)
+    ((char *) stream)[i] = 'a' + (char) ((cbc->up_pos + i)
+                                         % (unsigned char) ('z' - 'a' + 1));
+
+  cbc->up_pos += to_fill;
+  return to_fill;
+}
+
+
 static size_t
 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
 {
   struct CBC *cbc = ctx;
 
-  if (cbc->pos + size * nmemb > cbc->size)
+  if (cbc->dn_pos + size * nmemb > cbc->dn_buf_size)
     return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
+  memcpy (&cbc->dn_buf[cbc->dn_pos], ptr, size * nmemb);
+  cbc->dn_pos += size * nmemb;
   return size * nmemb;
 }
 
 
+#define TEST_MAGIC_MARKER0 0xFEE1C0DE
+#define TEST_MAGIC_MARKER1 (TEST_MAGIC_MARKER0 + 1)
+#define TEST_MAGIC_MARKER2 (TEST_MAGIC_MARKER0 + 2)
+
+struct content_cb_param_strct
+{
+  unsigned int magic0;    /**< Must have TEST_MAGIC_MARKER0 value */
+  struct MHD_Response *response; /**< The pointer to the response structure */
+};
+
+/**
+ * MHD content reader callback that returns
+ * data in chunks.
+ */
+static ssize_t
+content_cb (void *cls, uint64_t pos, char *buf, size_t max)
+{
+  struct content_cb_param_strct *param = (struct content_cb_param_strct *) cls;
+  size_t fill_size;
+
+  if ((unsigned int) TEST_MAGIC_MARKER0 != param->magic0)
+  {
+    fprintf (stderr, "Wrong cls pointer "
+             "at line %d.\n", (int) __LINE__);
+    fflush (stderr);
+    abort ();
+  }
+
+  if (pos >= 128 * 10)
+  {
+    if (MHD_YES !=
+        MHD_add_response_footer (param->response, "Footer", "working"))
+    {
+      fprintf (stderr, "MHD_add_response_footer() failed "
+               "at line %d.\n", (int) __LINE__);
+      fflush (stderr);
+      abort ();
+    }
+    return MHD_CONTENT_READER_END_OF_STREAM;
+  }
+
+  if (128 > max)
+    fill_size = 128;
+  else
+    fill_size = max;
+  memset (buf, 'A' + (char) (unsigned int) (pos / 128), fill_size);
+
+  return (ssize_t) fill_size;
+}
+
+
+/**
+ * Deallocate memory for callback cls.
+ */
+static void
+crcf (void *ptr)
+{
+  free (ptr);
+}
+
+
+struct req_process_strct
+{
+  unsigned int magic2;   /**< Must have TEST_MAGIC_MARKER2 value */
+  int is_static;         /**< Non-zero if statically allocated, zero if 
malloc()'ed */
+  struct MHD_PostProcessor *postprocsr;
+  unsigned int post_data_sum;
+};
+
+static enum MHD_Result
+post_iterator (void *cls,
+               enum MHD_ValueKind kind,
+               const char *key,
+               const char *filename,
+               const char *content_type,
+               const char *transfer_encoding,
+               const char *value, uint64_t off, size_t size)
+{
+  struct req_process_strct *param = (struct req_process_strct *) cls;
+  size_t i;
+
+  (void) filename; (void) content_type; (void) transfer_encoding;
+  (void) off; /* Unused. Mute compiler warnings. */
+
+  if (TEST_MAGIC_MARKER2 != param->magic2)
+  {
+    fprintf (stderr, "The 'param->magic2' has wrong value "
+             "at line %d.\n", (int) __LINE__);
+    abort ();
+  }
+
+  if (MHD_POSTDATA_KIND != kind)
+  {
+    fprintf (stderr, "The 'kind' parameter has wrong value "
+             "at line %d.\n", (int) __LINE__);
+    abort ();
+  }
+
+  if (NULL != key)
+    param->post_data_sum += (unsigned int) strlen (key);
+
+  for (i = 0; size > i; ++i)
+    param->post_data_sum += (unsigned int) (unsigned char) value[i];
+
+  return MHD_YES;
+}
+
+
+static void
+free_req_pr_data (struct req_process_strct *pr_data)
+{
+  if (NULL == pr_data)
+    return;
+  if (TEST_MAGIC_MARKER2 != pr_data->magic2)
+  {
+    fprintf (stderr, "The 'pr_data->magic2' has wrong value "
+             "at line %d.\n", (int) __LINE__);
+    abort ();
+  }
+  if (pr_data->is_static)
+  {
+    if (NULL != pr_data->postprocsr)
+    {
+      fprintf (stderr, "The 'pr_data->postprocsr' has wrong value "
+               "at line %d.\n", (int) __LINE__);
+      abort ();
+    }
+    return;
+  }
+  if (NULL != pr_data->postprocsr)
+    MHD_destroy_post_processor (pr_data->postprocsr);
+  pr_data->postprocsr = NULL;
+  free (pr_data);
+}
+
+
+struct ahc_param_strct
+{
+  unsigned int magic1;   /**< Must have TEST_MAGIC_MARKER1 value */
+  unsigned int err_flag; /**< Non-zero if any error is encountered */
+  unsigned int num_replies; /**< The number of replies sent for the current 
request */
+};
+
+static enum MHD_Result
+send_error_response (struct MHD_Connection *connection,
+                     struct ahc_param_strct *param,
+                     unsigned int status_code,
+                     const char *static_text,
+                     const size_t static_text_len)
+{
+  struct MHD_Response *response;
+  response =
+    MHD_create_response_from_buffer_static (static_text_len,
+                                            static_text);
+  if (NULL != response)
+  {
+    if (MHD_YES == MHD_add_response_header (response,
+                                            MHD_HTTP_HEADER_CONNECTION,
+                                            "close"))
+    {
+      if (MHD_YES == MHD_queue_response (connection, status_code, response))
+      {
+        MHD_destroy_response (response);
+        return MHD_YES; /* Success exit point */
+      }
+      else
+        fprintf (stderr, "MHD_queue_response() failed "
+                 "at line %d.\n", (int) __LINE__);
+    }
+    else
+      fprintf (stderr, "MHD_add_response_header() failed "
+               "at line %d.\n", (int) __LINE__);
+    MHD_destroy_response (response);
+  }
+  else
+    fprintf (stderr, "MHD_create_response_from_callback() failed "
+             "at line %d.\n", (int) __LINE__);
+
+  param->err_flag = 1;
+  return MHD_NO; /* Failure exit point */
+}
+
+
 static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
+ahc_check (void *cls,
+           struct MHD_Connection *connection,
+           const char *url,
+           const char *method,
+           const char *version,
+           const char *upload_data, size_t *upload_data_size,
+           void **req_cls)
 {
-  static int ptr;
-  const char *me = cls;
+  static struct req_process_strct static_req_pr_data = {
+    TEST_MAGIC_MARKER2, ! 0, NULL, 0
+  };
+  struct req_process_strct *req_pr_data;
+  struct ahc_param_strct *param = (struct ahc_param_strct *) cls;
   struct MHD_Response *response;
   enum MHD_Result ret;
-  (void) version; (void) upload_data; (void) upload_data_size;       /* 
Unused. Silent compiler warning. */
+  unsigned char data_sum;
+  int is_post_req;
 
+  if (NULL == cls)
+  {
+    fprintf (stderr, "The 'cls' parameter is NULL "
+             "at line %d.\n", (int) __LINE__);
+    fflush (stderr);
+    abort ();
+  }
+  if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1)
+  {
+    fprintf (stderr, "The 'param->magic1' has wrong value "
+             "at line %d.\n", (int) __LINE__);
+    fflush (stderr);
+    abort ();
+  }
+  if (NULL == connection)
+  {
+    fprintf (stderr, "The 'connection' parameter is NULL "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+    return MHD_NO; /* Should not reply */
+  }
+  if (1)
+  { /* Simple check for 'connection' parameter validity */
+    const union MHD_ConnectionInfo *conn_info;
+    conn_info =
+      MHD_get_connection_info (connection,
+                               MHD_CONNECTION_INFO_CONNECTION_TIMEOUT);
+    if (NULL == conn_info)
+    {
+      fprintf (stderr, "The 'MHD_get_connection_info' has returned NULL "
+               "at line %d.\n", (int) __LINE__);
+      param->err_flag = 1;
+    }
+    else if (MHD_TIMEOUT != conn_info->connection_timeout)
+    {
+      fprintf (stderr, "The 'MHD_get_connection_info' has returned "
+               "unexpected timeout value "
+               "at line %d.\n", (int) __LINE__);
+      param->err_flag = 1;
+    }
+  }
   if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
+  {
+    fprintf (stderr, "The 'url' parameter is NULL "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+  }
   if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
+  {
+    fprintf (stderr, "The 'method' parameter is NULL "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+    return MHD_NO; /* Should not reply */
+  }
   if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
+  {
+    fprintf (stderr, "The 'version' parameter is NULL "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+    return MHD_NO; /* Should not reply */
+  }
   if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
+  {
+    fprintf (stderr, "The 'upload_data_size' parameter is NULL "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+    return MHD_NO; /* Should not reply */
+  }
   if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp (me, method))
-    return MHD_NO;              /* unexpected method */
-  if (&ptr != *req_cls)
   {
-    *req_cls = &ptr;
+    fprintf (stderr, "The 'upload_data' parameter is NULL "
+             "while '*upload_data_size' is not zero "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+    return MHD_NO; /* Should not reply */
+  }
+  if ((NULL != upload_data) && (0 == *upload_data_size))
+  {
+    fprintf (stderr, "The 'upload_data' parameter is NOT NULL "
+             "while '*upload_data_size' is zero "
+             "at line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+    return MHD_NO; /* Should not reply */
+  }
+
+  if (0 != param->num_replies)
+  {
+    /* Phantom "second" request due to the fuzzing of the input. Refuse. */
+    return MHD_NO;
+  }
+
+  is_post_req = (0 == strcmp (method, MHD_HTTP_METHOD_POST));
+  if ((0 != strcmp (method, MHD_HTTP_METHOD_GET))
+      && (0 != strcmp (method, MHD_HTTP_METHOD_HEAD))
+      && (0 != strcmp (method, MHD_HTTP_METHOD_PUT))
+      && (! is_post_req))
+  {
+    /* Unsupported method for this callback */
+    return send_error_response (connection, param, MHD_HTTP_NOT_IMPLEMENTED,
+                                METHOD_NOT_SUPPORTED,
+                                MHD_STATICSTR_LEN_ (METHOD_NOT_SUPPORTED));
+  }
+
+  if (NULL == *req_cls)
+  {
+    if (! is_post_req)
+    { /* Use static memory */
+      *req_cls = &static_req_pr_data;
+    }
+    else
+    { /* POST request, use PostProcessor */
+      req_pr_data =
+        (struct req_process_strct *) malloc (sizeof (struct 
req_process_strct));
+      if (NULL == req_pr_data)
+      {
+        fprintf (stderr, "malloc() failed "
+                 "at line %d.\n", (int) __LINE__);
+        return MHD_NO;
+      }
+      req_pr_data->magic2 = TEST_MAGIC_MARKER2;
+      req_pr_data->is_static = 0;
+      req_pr_data->post_data_sum = 0;
+      req_pr_data->postprocsr = MHD_create_post_processor (connection, 1024,
+                                                           &post_iterator,
+                                                           req_pr_data);
+      if (NULL == req_pr_data->postprocsr)
+      {
+        free (req_pr_data);
+        if (NULL == upload_data)
+          return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST,
+                                      POST_DATA_BROKEN,
+                                      MHD_STATICSTR_LEN_ (POST_DATA_BROKEN));
+        else
+          return MHD_NO; /* Cannot handle request, broken POST */
+      }
+      *req_cls = req_pr_data;
+    }
+    if (NULL == upload_data)
+      return MHD_YES;
+  }
+  req_pr_data = (struct req_process_strct *) *req_cls;
+
+  data_sum = 0;
+  if (NULL != upload_data)
+  {
+    if (is_post_req)
+    {
+      if (MHD_YES != MHD_post_process (req_pr_data->postprocsr,
+                                       upload_data, *upload_data_size))
+      {
+        free_req_pr_data (req_pr_data);
+        *req_cls = NULL;
+        /* Processing upload body (context), error reply cannot be queued here 
*/
+        return MHD_NO;
+      }
+      *upload_data_size = 0; /* All data have been processed */
+    }
+    else
+    {
+      /* Check that all 'upload_data' is addressable */
+      size_t pos;
+      for (pos = 0; pos < *upload_data_size; ++pos)
+        data_sum += (unsigned char) upload_data[pos];
+      if (0 != *upload_data_size)
+      {
+        if (3 >= *upload_data_size)
+          *upload_data_size = 0;                             /* Consume all 
incoming data */
+        else
+          *upload_data_size = data_sum % *upload_data_size;  /* Pseudo-random 
*/
+      }
+    }
     return MHD_YES;
   }
+  if (is_post_req)
+  {
+    if (MHD_YES != MHD_destroy_post_processor (req_pr_data->postprocsr))
+    {
+      free (req_pr_data);
+      *req_cls = NULL;
+      return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST,
+                                  POST_DATA_BROKEN,
+                                  MHD_STATICSTR_LEN_ (POST_DATA_BROKEN));
+    }
+    req_pr_data->postprocsr = NULL;
+  }
+  data_sum += (unsigned char) req_pr_data->post_data_sum;
+  free_req_pr_data (req_pr_data);
   *req_cls = NULL;
-  response = MHD_create_response_from_buffer (strlen (url),
-                                              (void *) url,
-                                              MHD_RESPMEM_MUST_COPY);
-  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-  MHD_destroy_response (response);
-  if (ret == MHD_NO)
+
+  ret = MHD_YES;
+  if (use_get_chunked)
+  {
+    struct content_cb_param_strct *cnt_cb_param;
+    cnt_cb_param = malloc (sizeof (struct content_cb_param_strct));
+    if (NULL == cnt_cb_param)
+    {
+      fprintf (stderr, "malloc() failed "
+               "at line %d.\n", (int) __LINE__);
+      /* External error, do not rise the error flag */
+      return MHD_NO;
+    }
+    cnt_cb_param->magic0 = (unsigned int) TEST_MAGIC_MARKER0;
+    response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
+                                                  1024,
+                                                  &content_cb, cnt_cb_param,
+                                                  &crcf);
+    if (NULL == response)
+    {
+      fprintf (stderr, "MHD_create_response_from_callback() failed "
+               "at line %d.\n", (int) __LINE__);
+      free (cnt_cb_param);
+      param->err_flag = 1;
+      ret = MHD_NO;
+    }
+    else
+      cnt_cb_param->response = response;
+  }
+  else if (use_get || use_put || use_post)
+  {
+    /* Randomly choose the response page for the POST requests */
+    if (0 == data_sum % 2)
+      response =
+        MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ 
(EMPTY_PAGE),
+                                                EMPTY_PAGE);
+    else
+      response =
+        MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ ( \
+                                                  EMPTY_PAGE_ALT),
+                                                EMPTY_PAGE_ALT);
+
+    if (NULL == response)
+    {
+      fprintf (stderr, "MHD_create_response_from_buffer_static() failed "
+               "at line %d.\n", (int) __LINE__);
+      param->err_flag = 1;
+      ret = MHD_NO;
+    }
+  }
+  else
+  {
+    fprintf (stderr, "Response is not implemented for this test. "
+             "Internal logic is broken. "
+             "At line %d.\n", (int) __LINE__);
     abort ();
+  }
+
+  if (NULL != response)
+  {
+    if ((MHD_YES == ret) &&
+        (use_close || (! oneone && (0 != strcmp (version,
+                                                 MHD_HTTP_VERSION_1_0)))))
+    {
+      ret = MHD_add_response_header (response,
+                                     MHD_HTTP_HEADER_CONNECTION,
+                                     "close");
+      if (MHD_YES != ret)
+      {
+        fprintf (stderr, "MHD_add_response_header() failed "
+                 "at line %d.\n", (int) __LINE__);
+        param->err_flag = 1;
+      }
+    }
+    if (MHD_YES == ret)
+    {
+      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+      if (MHD_YES != ret)
+      {
+        fprintf (stderr, "MHD_queue_response() failed "
+                 "at line %d.\n", (int) __LINE__);
+        param->err_flag = 1;
+      }
+    }
+    else
+      param->num_replies++;
+
+    MHD_destroy_response (response);
+  }
+  else
+  {
+    fprintf (stderr, "MHD_create_response_from_buffer_static() failed "
+             "at line %d.\n", (int) __LINE__);
+    ret = MHD_NO;
+  }
   return ret;
 }
 
 
-static unsigned int
-testInternalGet ()
+static void
+req_completed_cleanup (void *cls,
+                       struct MHD_Connection *connection,
+                       void **req_cls,
+                       enum MHD_RequestTerminationCode toe)
+{
+  struct ahc_param_strct *param = (struct ahc_param_strct *) cls;
+  struct req_process_strct *req_pr_data = (struct req_process_strct *) 
*req_cls;
+  (void) connection; /* Unused. Mute compiler warning. */
+
+  if (NULL == param)
+  {
+    fprintf (stderr, "The 'cls' parameter is NULL at line %d.\n",
+             (int) __LINE__);
+    fflush (stderr);
+    abort ();
+  }
+  if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1)
+  {
+    fprintf (stderr, "The 'param->magic1' has wrong value at line %d.\n",
+             (int) __LINE__);
+    fflush (stderr);
+    abort ();
+  }
+  if (NULL == req_pr_data)
+    return; /* The data have been freed */
+  if ((unsigned int) TEST_MAGIC_MARKER2 != req_pr_data->magic2)
+  {
+    fprintf (stderr, "The 'req_pr_data->magic2' has wrong value at line %d.\n",
+             (int) __LINE__);
+    fflush (stderr);
+    abort ();
+  }
+  if (MHD_REQUEST_TERMINATED_COMPLETED_OK == toe)
+  {
+    fprintf (stderr, "The request completed successful, but request cls has"
+             "not been cleared. "
+             "At line %d.\n", (int) __LINE__);
+    param->err_flag = 1;
+  }
+  if (req_pr_data->is_static)
+    return;
+  if (NULL != req_pr_data->postprocsr)
+    MHD_destroy_post_processor (req_pr_data->postprocsr);
+  req_pr_data->postprocsr = NULL;
+  free (req_pr_data);
+  *req_cls = NULL;
+}
+
+
+/* Un-comment the next line (or use CPPFLAGS) to avoid
+   logging of the traffic with debug builds */
+/* #define TEST_NO_PRINT_TRAFFIC 1 */
+
+#ifdef _DEBUG
+#ifdef TEST_PRINT_BODY
+#ifndef TEST_PRINT_BODY_RQ
+#define TEST_PRINT_BODY_RQ 1
+#endif /* TEST_PRINT_BODY_RQ */
+#ifndef TEST_PRINT_BODY_RP
+#define TEST_PRINT_BODY_RP 1
+#endif /* TEST_PRINT_BODY_RP */
+#endif /* TEST_PRINT_BODY */
+#endif /* _DEBUG */
+
+static int
+libcurl_debug_cb (CURL *handle,
+                  curl_infotype type,
+                  char *data,
+                  size_t size,
+                  void *ctx)
+{
+  static const char excess_mark[] = "Excess found";
+  static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
+  struct CBC *cbc = ctx;
+  (void) handle;
+
+#if defined(_DEBUG) && ! defined(TEST_NO_PRINT_TRAFFIC)
+  switch (type)
+  {
+  case CURLINFO_TEXT:
+    fprintf (stderr, "* %.*s", (int) size, data);
+    break;
+  case CURLINFO_HEADER_IN:
+    fprintf (stderr, "< %.*s", (int) size, data);
+    break;
+  case CURLINFO_HEADER_OUT:
+    fprintf (stderr, "> %.*s", (int) size, data);
+    break;
+  case CURLINFO_DATA_IN:
+#ifdef TEST_PRINT_BODY_RP
+    fprintf (stderr, "<| %.*s\n", (int) size, data);
+#endif /* TEST_PRINT_BODY_RP */
+    break;
+  case CURLINFO_DATA_OUT:
+#ifdef TEST_PRINT_BODY_RQ
+    fprintf (stderr, ">| %.*s\n", (int) size, data);
+#endif /* TEST_PRINT_BODY_RQ */
+    break;
+  case CURLINFO_SSL_DATA_IN:
+  case CURLINFO_SSL_DATA_OUT:
+  case CURLINFO_END:
+  default:
+    break;
+  }
+#endif /* _DEBUG  && ! TEST_NO_PRINT_TRAFFIC */
+  if (use_close || ! oneone)
+  {
+    /* Check for extra data only if every connection is terminated by MHD
+       after one request, otherwise MHD may react on garbage after request
+       data. */
+    if (CURLINFO_TEXT == type)
+    {
+      if ((size >= excess_mark_len) &&
+          (0 == memcmp (data, excess_mark, excess_mark_len)))
+      {
+        fprintf (stderr, "Extra data has been detected in MHD reply "
+                 "at line %d.\n", (int) __LINE__);
+        cbc->excess_found++;
+      }
+    }
+  }
+  return 0;
+}
+
+
+static CURL *
+setupCURL (struct CBC *cbc, uint16_t port
+#ifndef TEST_USE_STATIC_POST_DATA
+           , curl_mime **mime
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+           )
 {
-  struct MHD_Daemon *d;
   CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  CURLcode e;
+  char *buf;
+  const char *uri_to_use;
+  const char *base_uri;
+
+#ifndef TEST_USE_STATIC_POST_DATA
+  *mime = NULL;
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+
+  base_uri = run_with_socat ? TEST_BASE_URI_SOCAT : TEST_BASE_URI;
+  if (! use_long_uri)
+  {
+    uri_to_use = base_uri;
+    buf = NULL;
+  }
+  else
+  {
+    size_t pos;
+    size_t base_uri_len;
+
+    base_uri_len = strlen (base_uri);
+    buf = malloc (TEST_STRING_VLONG_LEN + 1);
+    if (NULL == buf)
+    {
+      fprintf (stderr, "malloc() failed "
+               "at line %d.\n", (int) __LINE__);
+      return NULL;
+    }
+    memcpy (buf, base_uri, base_uri_len);
+    for (pos = base_uri_len;
+         pos < TEST_STRING_VLONG_LEN;
+         ++pos)
+    {
+      if (0 == pos % 9)
+        buf[pos] = '/';
+      else
+        buf[pos] = 'a' + (char) (unsigned char) (pos % ((unsigned char)
+                                                        ('z' - 'a' + 1)));
+    }
+    buf[TEST_STRING_VLONG_LEN] = 0;
+    uri_to_use = buf;
+  }
+  if (run_with_socat)
+    port = SOCAT_PORT;
+
+  c = curl_easy_init ();
+  if (NULL == c)
+  {
+    fprintf (stderr, "curl_easy_init() failed "
+             "at line %d.\n", (int) __LINE__);
+    return NULL;
+  }
+
+  if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_URL,
+                                          uri_to_use))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
+                                          &copyBuffer))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
+                                          ((long) CURL_TIMEOUT)))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
+                                          oneone ?
+                                          CURL_HTTP_VERSION_1_1 :
+                                          CURL_HTTP_VERSION_1_0))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_TIMEOUT,
+                                          ((long) CURL_TIMEOUT)))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L))) &&
+#ifdef _DEBUG
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_VERBOSE, 1L))) &&
+#endif /* _DEBUG */
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
+                                          &libcurl_debug_cb))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGDATA,
+                                          cbc))) &&
+#if CURL_AT_LEAST_VERSION (7, 19, 4)
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PROTOCOLS,
+                                          CURLPROTO_HTTP))) &&
+#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
+#if CURL_AT_LEAST_VERSION (7, 45, 0)
+      (CURLE_OK == (e = curl_easy_setopt (c,
+                                          CURLOPT_DEFAULT_PROTOCOL, "http"))) 
&&
+#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
+#if CURL_AT_LEAST_VERSION (7, 24, 0)
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE,
+                                          "host!127.0.0.101"))) &&
+#else  /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE,
+                                          "127.0.0.101"))) &&
+#endif /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) &&
+      (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTPHEADER,
+                                          use_long_header ?
+                                          libcurl_long_header : NULL)))
+      )
+  {
+    if (NULL != buf)
+    {
+      free (buf);
+      buf = NULL;
+    }
+    if (use_put)
+    {
+      if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READFUNCTION,
+                                              &putBuffer))) &&
+          (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READDATA, cbc))) &&
+          (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_UPLOAD, (long) 1))) &&
+          (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE,
+                                              use_put_chunked ?
+                                              ((curl_off_t) -1) :
+                                              ((curl_off_t) cbc->up_size)))))
+      {
+        return c; /* Success exit point for 'use_put' */
+      }
+      else
+        fprintf (stderr, "PUT-related curl_easy_setopt() failed at line %d, "
+                 "error: %s\n", (int) __LINE__,
+                 curl_easy_strerror (e));
+    }
+    else if (use_post)
+    {
+      if (! use_post_form)
+      {
+        if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POST, (long) 1))) &&
+            (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POSTFIELDS,
+                                                POST_URLENC_DATA))) &&
+            (CURLE_OK ==
+             (e = curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE,
+                                    MHD_STATICSTR_LEN_ (POST_URLENC_DATA)))))
+        {
+          return c; /* Success exit point for 'use_post' */
+        }
+        else
+          fprintf (stderr,
+                   "POST-related curl_easy_setopt() failed at line %d, "
+                   "error: %s\n", (int) __LINE__,
+                   curl_easy_strerror (e));
+      }
+      else
+      {
+#ifndef TEST_USE_STATIC_POST_DATA
+        *mime = curl_mime_init (c);
+        if (NULL != *mime)
+        {
+          curl_mimepart *part;
+          if ((NULL != (part = curl_mime_addpart (*mime))) &&
+              (CURLE_OK == curl_mime_name (part, POST_KEY1)) &&
+              (CURLE_OK == curl_mime_data (part, POST_VALUE1,
+                                           MHD_STATICSTR_LEN_ (POST_VALUE1))) 
&&
+              (NULL != (part = curl_mime_addpart (*mime))) &&
+              (CURLE_OK == curl_mime_name (part, POST_KEY2)) &&
+              (CURLE_OK == curl_mime_data (part, POST_VALUE2,
+                                           MHD_STATICSTR_LEN_ (POST_VALUE2))))
+          {
+            if (CURLE_OK ==
+                (e = curl_easy_setopt (c, CURLOPT_MIMEPOST, *mime)))
+              return c; /* Success exit point for 'use_post' */
+            else
+              fprintf (stderr, "curl_easy_setopt(c, CURLOPT_MIMEPOST, mime) "
+                       "failed at line %d, error: %s\n",
+                       (int) __LINE__, curl_easy_strerror (e));
+          }
+          else
+            fprintf (stderr, "curl_mime_addpart(), curl_mime_name() or "
+                     "curl_mime_data() failed.\n");
+        }
+        else
+          fprintf (stderr, "curl_mime_init() failed.\n");
+
+#else  /* TEST_USE_STATIC_POST_DATA */
+        if (CURLE_OK == (e = curl_easy_setopt (c,
+                                               CURLOPT_HTTPPOST, post_first)))
+        {
+          return c; /* Success exit point for 'use_post' */
+        }
+        else
+          fprintf (stderr, "POST form-related curl_easy_setopt() failed, "
+                   "error: %s\n", curl_easy_strerror (e));
+#endif /* TEST_USE_STATIC_POST_DATA */
+      }
+    }
     else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
+      return c; /* Success exit point */
   }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
+  else
+    fprintf (stderr, "curl_easy_setopt() failed at line %d, "
+             "error: %s\n", (int) __LINE__,
+             curl_easy_strerror (e));
+
+  curl_easy_cleanup (c);
+#ifndef TEST_USE_STATIC_POST_DATA
+  if (NULL != *mime)
+    curl_mime_free (*mime);
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+
+  if (NULL != buf)
+    free (buf);
+
+  return NULL; /* Failure exit point */
+}
+
+
+static struct MHD_Daemon *
+start_daemon_for_test (unsigned int daemon_flags, uint16_t *pport,
+                       struct ahc_param_strct *callback_param)
+{
+  struct MHD_Daemon *d;
+  struct MHD_OptionItem ops[] = {
+    { MHD_OPTION_END, 0, NULL },
+    { MHD_OPTION_END, 0, NULL }
+  };
+  callback_param->magic1 = (unsigned int) TEST_MAGIC_MARKER1;
+  callback_param->err_flag = 0;
+  callback_param->num_replies = 0;
+
+  if (use_put_large)
+  {
+    ops[0].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
+    ops[0].value = (intptr_t) (PUT_LARGE_SIZE / 4);
+  }
+  else if (use_long_header || use_long_uri)
+  {
+    ops[0].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
+    ops[0].value = (intptr_t) (TEST_STRING_VLONG_LEN / 2);
+  }
+  d = MHD_start_daemon (daemon_flags /* | MHD_USE_ERROR_LOG */,
+                        *pport, NULL, NULL,
+                        &ahc_check, callback_param,
+                        MHD_OPTION_CONNECTION_TIMEOUT,
+                        (unsigned int) MHD_TIMEOUT,
+                        MHD_OPTION_NOTIFY_COMPLETED,
+                        &req_completed_cleanup, callback_param,
+                        MHD_OPTION_ARRAY, ops,
+                        MHD_OPTION_END);
+  if (NULL == d)
+  {
+    fprintf (stderr, "MHD_start_daemon() failed "
+             "at line %d.\n", (int) __LINE__);
+    return NULL;
+  }
+
+  /* Do not use accept4() as only accept() is intercepted by zzuf */
+  if (! run_with_socat)
+    MHD_avoid_accept4_ (d);
+
+  if (0 == *pport)
+  {
+    const union MHD_DaemonInfo *dinfo;
+
+    dinfo = MHD_get_daemon_info (d,
+                                 MHD_DAEMON_INFO_BIND_PORT);
+    if ( (NULL == dinfo) ||
+         (0 == dinfo->port) )
+    {
+      fprintf (stderr, "MHD_get_daemon_info() failed "
+               "at line %d.\n", (int) __LINE__);
+      MHD_stop_daemon (d);
+      return NULL;
+    }
+    *pport = dinfo->port;
+  }
+  return d;
+}
+
+
+static void
+print_test_starting (unsigned int daemon_flags)
+{
+  fflush (stderr);
+  if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
+  {
+    if (0 != (MHD_USE_THREAD_PER_CONNECTION & daemon_flags))
+    {
+      if (0 != (MHD_USE_POLL & daemon_flags))
+        printf ("\nStarting test with internal polling by poll() and "
+                "thread-per-connection.\n");
+      else
+        printf ("\nStarting test with internal polling by select() and "
+                "thread-per-connection.\n");
+    }
+    else
+    {
+      if (0 != (MHD_USE_POLL & daemon_flags))
+        printf ("\nStarting test with internal polling by poll().\n");
+      else if (0 != (MHD_USE_EPOLL & daemon_flags))
+        printf ("\nStarting test with internal polling by 'epoll'.\n");
+      else
+        printf ("\nStarting test with internal polling by select().\n");
+    }
+  }
+  else
+  {
+    if (0 != (MHD_USE_EPOLL & daemon_flags))
+      printf ("\nStarting test with external polling and internal 'epoll'.\n");
+    else
+      printf ("\nStarting test with external polling.\n");
+  }
+  fflush (stdout);
 }
 
 
 static unsigned int
-testMultithreadedGet ()
+testInternalPolling (uint16_t *pport, unsigned int daemon_flags)
 {
   struct MHD_Daemon *d;
   CURL *c;
   char buf[2048];
   struct CBC cbc;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD /* | 
MHD_USE_ERROR_LOG */,
-                        11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  struct ahc_param_strct callback_param;
+  unsigned int ret;
+#ifndef TEST_USE_STATIC_POST_DATA
+  curl_mime *mime;
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+
+  if (0 == (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
+  {
+    fprintf (stderr, "Wrong internal flags, the test is broken. "
+             "At line %d.\n", (int) __LINE__);
+    abort (); /* Wrong flags, error in code */
+  }
+
+  print_test_starting (daemon_flags);
+  initCBC (&cbc, buf, sizeof(buf));
+  d = start_daemon_for_test (daemon_flags, pport, &callback_param);
   if (d == NULL)
-    return 16;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
+    return 1;
+
+  ret = 0;
+  c = setupCURL (&cbc, *pport
+#ifndef TEST_USE_STATIC_POST_DATA
+                 , &mime
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+                 );
+  if (NULL != c)
+  {
+    int i;
+
+    for (i = dry_run ? LOOP_COUNT : 0; i < LOOP_COUNT; i++)
+    {
+      fprintf (stderr, ".");
+      callback_param.num_replies = 0;
+      resetCBC (&cbc);
+      /* Run libcurl without checking the result */
+      curl_easy_perform (c);
+      fflush (stderr);
+    }
     curl_easy_cleanup (c);
+#ifndef TEST_USE_STATIC_POST_DATA
+    if (NULL != mime)
+      curl_mime_free (mime);
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+  }
+  else
+    ret = 99; /* Not an MHD error */
+
+  if ((0 == ret) && callback_param.err_flag)
+  {
+    fprintf (stderr, "One or more errors have been detected by "
+             "access handler callback function. "
+             "At line %d.\n", (int) __LINE__);
+    ret = 1;
+  }
+  else if ((0 == ret) && cbc.excess_found)
+  {
+    fprintf (stderr, "The extra reply data have been detected one "
+             "or more times. "
+             "At line %d.\n", (int) __LINE__);
+    ret = 1;
   }
+
   fprintf (stderr, "\n");
-  zzuf_socat_stop ();
   MHD_stop_daemon (d);
-  return 0;
+  fflush (stderr);
+  return ret;
 }
 
 
 static unsigned int
-testExternalGet ()
+testExternalPolling (uint16_t *pport, unsigned int daemon_flags)
 {
   struct MHD_Daemon *d;
-  CURL *c;
+  CURLM *multi;
   char buf[2048];
   struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  int i;
-
-  multi = NULL;
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
-                        11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  struct ahc_param_strct callback_param;
+  unsigned int ret;
+#ifndef TEST_USE_STATIC_POST_DATA
+  curl_mime *mime;
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+
+  if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags))
+  {
+    fprintf (stderr, "Wrong internal flags, the test is broken. "
+             "At line %d.\n", (int) __LINE__);
+    abort (); /* Wrong flags, error in code */
+  }
+
+  print_test_starting (daemon_flags);
+  initCBC (&cbc, buf, sizeof(buf));
+  d = start_daemon_for_test (daemon_flags, pport, &callback_param);
   if (d == NULL)
-    return 256;
+    return 1;
+
+  ret = 0;
   multi = curl_multi_init ();
   if (multi == NULL)
   {
-    MHD_stop_daemon (d);
-    return 512;
+    fprintf (stderr, "curl_multi_init() failed "
+             "at line %d.\n", (int) __LINE__);
+    ret = 99; /* Not an MHD error */
   }
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
+  else
   {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+    CURL *c;
+    c = setupCURL (&cbc, *pport
+#ifndef TEST_USE_STATIC_POST_DATA
+                   , &mime
+#endif /* ! TEST_USE_STATIC_POST_DATA */
+                   );
+
+    if (NULL == c)
+      ret = 99; /* Not an MHD error */
     else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
     {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
+      int i;
+
+      for (i = dry_run ? LOOP_COUNT : 0;
+           (i < LOOP_COUNT) && (0 == ret); i++)
       {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
+        CURLMcode mret;
+
+        /* The same 'multi' handle will be used in transfers so
+           connection will be reused.
+           The same 'easy' handle is added (and removed later) to (re-)start
+           the same transfer. */
+        mret = curl_multi_add_handle (multi, c);
+        if (CURLM_OK != mret)
+        {
+          fprintf (stderr, "curl_multi_add_handle() failed at %d, "
+                   "error: %s\n", (int) __LINE__,
+                   curl_multi_strerror (mret));
+          ret = 99; /* Not an MHD error */
+        }
+        else
+        {
+          time_t start;
+
+          fprintf (stderr, ".");
+          callback_param.num_replies = 0;
+          resetCBC (&cbc);
+          start = time (NULL);
+          do
+          {
+            fd_set rs;
+            fd_set ws;
+            fd_set es;
+            int maxfd_curl;
+            MHD_socket maxfd_mhd;
+            int maxfd;
+            int running;
+            struct timeval tv;
+
+            maxfd_curl = 0;
+            maxfd_mhd = MHD_INVALID_SOCKET;
+            FD_ZERO (&rs);
+            FD_ZERO (&ws);
+            FD_ZERO (&es);
+            curl_multi_perform (multi, &running);
+            if (0 == running)
+            {
+              int msgs_left;
+              do
+              {
+                (void) curl_multi_info_read (multi, &msgs_left);
+              } while (0 != msgs_left);
+              break; /* The transfer has been finished */
+            }
+            mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxfd_curl);
+            if (CURLM_OK != mret)
+            {
+              fprintf (stderr, "curl_multi_fdset() failed at line %d, "
+                       "error: %s\n", (int) __LINE__,
+                       curl_multi_strerror (mret));
+              ret = 99; /* Not an MHD error */
+              break;
+            }
+            if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxfd_mhd))
+            {
+              fprintf (stderr, "MHD_get_fdset() failed "
+                       "at line %d.\n", (int) __LINE__);
+              ret = 1;
+              break;
+            }
+#ifndef MHD_WINSOCK_SOCKETS
+            if ((int) maxfd_mhd > maxfd_curl)
+              maxfd = (int) maxfd_mhd;
+            else
+#endif /* ! MHD_WINSOCK_SOCKETS */
+            maxfd = maxfd_curl;
+            tv.tv_sec = 0;
+            tv.tv_usec = 100 * 1000;
+            if (0 == MHD_get_timeout64s (d))
+              tv.tv_usec = 0;
+            else
+            {
+              long curl_to = -1;
+              curl_multi_timeout (multi, &curl_to);
+              if (0 == curl_to)
+                tv.tv_usec = 0;
+            }
+            if (-1 == select (maxfd + 1, &rs, &ws, &es, &tv))
+            {
+#ifdef MHD_POSIX_SOCKETS
+              if (EINTR != errno)
+                fprintf (stderr, "Unexpected select() error "
+                         "at line %d.\n", (int) __LINE__);
+#else  /* ! MHD_POSIX_SOCKETS */
+              if ((WSAEINVAL != WSAGetLastError ()) ||
+                  (0 != rs.fd_count) || (0 != ws.fd_count) ||
+                  (0 != es.fd_count))
+                fprintf (stderr, "Unexpected select() error "
+                         "at line %d.\n", (int) __LINE__);
+              Sleep ((unsigned long) tv.tv_usec / 1000);
+#endif /* ! MHD_POSIX_SOCKETS */
+            }
+            MHD_run (d);
+          } while (time (NULL) - start <= MHD_TIMEOUT);
+          /* Remove 'easy' handle from 'multi' handle to
+           * restart the transfer or to finish. */
+          curl_multi_remove_handle (multi, c);
+        }
       }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
       curl_easy_cleanup (c);
     }
+    curl_multi_cleanup (multi);
+#ifndef TEST_USE_STATIC_POST_DATA
+    if (NULL != mime)
+      curl_mime_free (mime);
+#endif /* ! TEST_USE_STATIC_POST_DATA */
   }
+
+  if ((0 == ret) && callback_param.err_flag)
+  {
+    fprintf (stderr, "One or more errors have been detected by "
+             "access handler callback function. "
+             "At line %d.\n", (int) __LINE__);
+    ret = 1;
+  }
+  else if ((0 == ret) && cbc.excess_found)
+  {
+    fprintf (stderr, "The extra reply data have been detected one "
+             "or more times. "
+             "At line %d.\n", (int) __LINE__);
+    ret = 1;
+  }
+
   fprintf (stderr, "\n");
-  curl_multi_cleanup (multi);
-  zzuf_socat_stop ();
   MHD_stop_daemon (d);
   return 0;
 }
 
 
+static unsigned int
+run_all_checks (void)
+{
+  uint16_t port;
+  unsigned int testRes;
+  unsigned int ret = 0;
+
+  if (! run_with_socat)
+  {
+    if (MHD_are_sanitizers_enabled_ ())
+    {
+      fprintf (stderr, "Direct run with zzuf does not work with sanitizers. "
+               "At line %d.\n", (int) __LINE__);
+      return 77;
+    }
+    if (! MHD_is_avoid_accept4_possible_ ())
+    {
+      fprintf (stderr,
+               "Non-debug build of MHD on this platform use accept4() 
function. "
+               "Direct run with zzuf is not possible. "
+               "At line %d.\n", (int) __LINE__);
+      return 77;
+    }
+    if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
+      port = 0;     /* Use system automatic assignment */
+    else
+    {
+      port = TEST_BASE_PORT;  /* Use predefined port, may break parallel 
testing of another MHD build */
+      if (oneone)
+        port += 100;
+      if (use_long_uri)
+        port += 30;
+      else if (use_long_header)
+        port += 35;
+      else if (use_get_chunked)
+        port += 0;
+      else if (use_get)
+        port += 5;
+      else if (use_post_form)
+        port += 10;
+      else if (use_post)
+        port += 15;
+      else if (use_put_large)
+        port += 20;
+      else if (use_put_chunked)
+        port += 25;
+    }
+  }
+  else
+    port = TEST_BASE_PORT;  /* Use predefined port, may break parallel testing 
of another MHD build */
+
+  if (! dry_run && (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)))
+  {
+    testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY);
+    if ((77 == testRes) || (99 == testRes))
+      return testRes;
+    ret += testRes;
+    testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY
+                                   | MHD_USE_THREAD_PER_CONNECTION);
+    if ((77 == testRes) || (99 == testRes))
+      return testRes;
+    ret += testRes;
+
+    if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL))
+    {
+      testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY);
+      if ((77 == testRes) || (99 == testRes))
+        return testRes;
+      ret += testRes;
+      testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY
+                                     | MHD_USE_THREAD_PER_CONNECTION);
+      if ((77 == testRes) || (99 == testRes))
+        return testRes;
+      ret += testRes;
+    }
+
+    if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
+    {
+      testRes = testInternalPolling (&port, MHD_USE_EPOLL_INTERNALLY);
+      if ((77 == testRes) || (99 == testRes))
+        return testRes;
+    }
+  }
+  testRes = testExternalPolling (&port, MHD_NO_FLAG);
+  if ((77 == testRes) || (99 == testRes))
+    return testRes;
+  ret += testRes;
+
+  return ret;
+}
+
+
 int
 main (int argc, char *const *argv)
 {
-  unsigned int errorCount = 0;
-  (void) argc;   /* Unused. Silent compiler warning. */
+  unsigned int res;
+  int use_magic_exit_codes;
+
+  oneone = ! has_in_name (argv[0], "10");
+  use_get = has_in_name (argv[0], "_get");
+  use_get_chunked = has_in_name (argv[0], "_get_chunked");
+  use_put = has_in_name (argv[0], "_put");
+  use_put_large = has_in_name (argv[0], "_put_large");
+  use_put_chunked = has_in_name (argv[0], "_put_chunked");
+  use_post = has_in_name (argv[0], "_post");
+  use_post_form = has_in_name (argv[0], "_post_form");
+  use_long_header = has_in_name (argv[0], "_long_header");
+  use_long_uri = has_in_name (argv[0], "_long_uri");
+  use_close = has_in_name (argv[0], "_close");
 
-  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
-           (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
+  run_with_socat = has_param (argc, argv, "--with-socat");
+  dry_run = has_param (argc, argv, "--dry-run") ||
+            has_param (argc, argv, "-n");
+
+  if (1 !=
+      ((use_get ? 1 : 0) + (use_put ? 1 : 0) + (use_post ? 1 : 0)))
   {
-    errorCount += testInternalGet ();
-    errorCount += testMultithreadedGet ();
+    fprintf (stderr, "Wrong test name '%s': no or multiple indications "
+             "for the test type.\n", argv[0] ? argv[0] : "(NULL)");
+    return 99;
   }
-  errorCount += testExternalGet ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
+  use_magic_exit_codes = run_with_socat || dry_run;
+
+  /* zzuf cannot bypass exit values.
+     Unless 'dry run' is used, do not return errors for external error
+     conditions (like out-of-memory) as they will be reported as test 
failures. */
+  if (! test_global_init ())
+    return use_magic_exit_codes ? 99 : 0;
+  res = run_all_checks ();
+  test_global_deinit ();
+  if (99 == res)
+    return use_magic_exit_codes ? 99 : 0;
+  if (77 == res)
+    return use_magic_exit_codes ? 77 : 0;
+  return (0 == res) ? 0 : 1;       /* 0 == pass */
 }
diff --git a/src/testzzuf/test_get_chunked.c b/src/testzzuf/test_get_chunked.c
deleted file mode 100644
index 8013494f..00000000
--- a/src/testzzuf/test_get_chunked.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file daemontest_get_chunked.c
- * @brief  Testcase for libmicrohttpd GET operations with chunked content 
encoding
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-#include "socat.c"
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  struct CBC *cbc = ctx;
-
-  if (cbc->pos + size * nmemb > cbc->size)
-    return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
-  return size * nmemb;
-}
-
-
-/**
- * MHD content reader callback that returns
- * data in chunks.
- */
-static ssize_t
-crc (void *cls, uint64_t pos, char *buf, size_t max)
-{
-  struct MHD_Response **responseptr = cls;
-
-  if (pos == 128 * 10)
-  {
-    MHD_add_response_header (*responseptr, "Footer", "working");
-    return MHD_CONTENT_READER_END_OF_STREAM;
-  }
-  if (max < 128)
-    abort ();                   /* should not happen in this testcase... */
-  memset (buf, 'A' + (pos / 128), 128);
-  return 128;
-}
-
-
-/**
- * Dummy function that does nothing.
- */
-static void
-crcf (void *ptr)
-{
-  free (ptr);
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size, void **req_cls)
-{
-  static int aptr;
-  const char *me = cls;
-  struct MHD_Response *response;
-  struct MHD_Response **responseptr;
-  enum MHD_Result ret;
-
-  (void) url;
-  (void) version;              /* Unused. Silent compiler warning. */
-  (void) upload_data;
-  (void) upload_data_size;     /* Unused. Silent compiler warning. */
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp (me, method))
-    return MHD_NO;              /* unexpected method */
-  if (&aptr != *req_cls)
-  {
-    /* do never respond on first call */
-    *req_cls = &aptr;
-    return MHD_YES;
-  }
-  responseptr = malloc (sizeof (struct MHD_Response *));
-  if (NULL == responseptr)
-    return MHD_NO;
-  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
-                                                1024,
-                                                &crc, responseptr, &crcf);
-  if (NULL == response)
-  {
-    free (responseptr);
-    return MHD_NO;
-  }
-  *responseptr = response;
-  ret = MHD_queue_response (connection,
-                            MHD_HTTP_OK,
-                            response);
-  MHD_destroy_response (response);
-  return ret;
-}
-
-
-static unsigned int
-testInternalGet ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testMultithreadedGet ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD /* | 
MHD_USE_ERROR_LOG */,
-                        11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testExternalGet ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  int i;
-
-  multi = NULL;
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
-                        11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
-  if (d == NULL)
-    return 256;
-  multi = curl_multi_init ();
-  if (multi == NULL)
-  {
-    MHD_stop_daemon (d);
-    return 512;
-  }
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
-    {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
-      {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
-      }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
-      curl_easy_cleanup (c);
-    }
-  }
-  fprintf (stderr, "\n");
-  curl_multi_cleanup (multi);
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  (void) argc; (void) argv; /* Unused. Silent compiler warning. */
-
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
-  {
-    errorCount += testInternalGet ();
-    errorCount += testMultithreadedGet ();
-  }
-  errorCount += testExternalGet ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/test_long_header.c b/src/testzzuf/test_long_header.c
deleted file mode 100644
index c0259398..00000000
--- a/src/testzzuf/test_long_header.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_long_header.c
- * @brief  Testcase for libmicrohttpd handling of very long headers
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-#include "socat.c"
-
-/**
- * We will set the memory available per connection to
- * half of this value, so the actual value does not have
- * to be big at all...
- */
-#define VERY_LONG (1024 * 10)
-
-static int oneone;
-
-static enum MHD_Result
-apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
-{
-  (void) cls; (void) addr; (void) addrlen;   /* Unused. Silent compiler 
warning. */
-  return MHD_YES;
-}
-
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  (void) ptr; (void) ctx;  /* Unused. Silent compiler warning. */
-  return size * nmemb;
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  const char *me = cls;
-  struct MHD_Response *response;
-  enum MHD_Result ret;
-  (void) version; (void) upload_data;      /* Unused. Silent compiler warning. 
*/
-  (void) upload_data_size; (void) req_cls; /* Unused. Silent compiler warning. 
*/
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp (me, method))
-    return MHD_NO;              /* unexpected method */
-  response = MHD_create_response_from_buffer (strlen (url),
-                                              (void *) url,
-                                              MHD_RESPMEM_MUST_COPY);
-  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-  MHD_destroy_response (response);
-  return ret;
-}
-
-
-static unsigned int
-testLongUrlGet ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  char *url;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080,
-                      &apc_all,
-                      NULL,
-                      &ahc_echo,
-                      "GET",
-                      MHD_OPTION_CONNECTION_MEMORY_LIMIT,
-                      (size_t) (VERY_LONG / 2), MHD_OPTION_END);
-
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    url = malloc (VERY_LONG);
-    if (NULL == url)
-    {
-      zzuf_socat_stop ();
-      return 1;
-    }
-    memset (url, 'a', VERY_LONG);
-    url[VERY_LONG - 1] = '\0';
-    memcpy (url, "http://127.0.0.1:11081/";,
-            strlen ("http://127.0.0.1:11081/";));
-    curl_easy_setopt (c, CURLOPT_URL, url);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-    free (url);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testLongHeaderGet ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  char *url;
-  struct curl_slist *header = NULL;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080,
-                      &apc_all,
-                      NULL,
-                      &ahc_echo,
-                      "GET",
-                      MHD_OPTION_CONNECTION_MEMORY_LIMIT,
-                      (size_t) (VERY_LONG / 2), MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    url = malloc (VERY_LONG);
-    if (NULL == url)
-    {
-      zzuf_socat_stop ();
-      curl_easy_cleanup (c);
-      return 16;
-    }
-    memset (url, 'a', VERY_LONG);
-    url[VERY_LONG - 1] = '\0';
-    url[VERY_LONG / 2] = ':';
-    url[VERY_LONG / 2 + 1] = ' ';
-    header = curl_slist_append (header, url);
-
-    curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_slist_free_all (header);
-    header = NULL;
-    curl_easy_cleanup (c);
-    free (url);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  const char *sl;
-  (void) argc;   /* Unused. Silent compiler warning. */
-
-  sl = strrchr (argv[0], (int) '/');
-  oneone = (NULL != sl) ? (NULL != strstr (sl, "11")) : 0;
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  errorCount += testLongUrlGet ();
-  errorCount += testLongHeaderGet ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/test_post.c b/src/testzzuf/test_post.c
deleted file mode 100644
index 895c5fce..00000000
--- a/src/testzzuf/test_post.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_post.c
- * @brief  Testcase for libmicrohttpd POST operations using URL-encoding
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-
-#include "socat.c"
-
-#define POST_DATA "name=daniel&project=curl"
-
-static int oneone;
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-
-static void
-completed_cb (void *cls,
-              struct MHD_Connection *connection,
-              void **req_cls,
-              enum MHD_RequestTerminationCode toe)
-{
-  struct MHD_PostProcessor *pp = *req_cls;
-  (void) cls; (void) connection; (void) toe; /* Unused. Silent compiler 
warning. */
-
-  if (NULL != pp)
-    MHD_destroy_post_processor (pp);
-  *req_cls = NULL;
-}
-
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  struct CBC *cbc = ctx;
-
-  if (cbc->pos + size * nmemb > cbc->size)
-    return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
-  return size * nmemb;
-}
-
-
-/**
- * Note that this post_iterator is not perfect
- * in that it fails to support incremental processing.
- * (to be fixed in the future)
- */
-static enum MHD_Result
-post_iterator (void *cls,
-               enum MHD_ValueKind kind,
-               const char *key,
-               const char *filename,
-               const char *content_type,
-               const char *transfer_encoding,
-               const char *value, uint64_t off, size_t size)
-{
-  int *eok = cls;
-  (void) kind; (void) filename; (void) content_type; /* Unused. Silent 
compiler warning. */
-  (void) transfer_encoding; (void) off;            /* Unused. Silent compiler 
warning. */
-
-  if ((0 == strcmp (key, "name")) &&
-      (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
-    (*eok) |= 1;
-  if ((0 == strcmp (key, "project")) &&
-      (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
-    (*eok) |= 2;
-  return MHD_YES;
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  static int eok;
-  struct MHD_Response *response;
-  struct MHD_PostProcessor *pp;
-  enum MHD_Result ret;
-  (void) cls; (void) version;      /* Unused. Silent compiler warning. */
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp ("POST", method))
-  {
-    return MHD_NO;              /* unexpected method */
-  }
-  pp = *req_cls;
-  if (pp == NULL)
-  {
-    eok = 0;
-    pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
-    *req_cls = pp;
-  }
-  MHD_post_process (pp, upload_data, *upload_data_size);
-  if ((eok == 3) && (0 == *upload_data_size))
-  {
-    response = MHD_create_response_from_buffer (strlen (url),
-                                                (void *) url,
-                                                MHD_RESPMEM_MUST_COPY);
-    ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-    MHD_destroy_response (response);
-    MHD_destroy_post_processor (pp);
-    *req_cls = NULL;
-    return ret;
-  }
-  *upload_data_size = 0;
-  return MHD_YES;
-}
-
-
-static unsigned int
-testInternalPost ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080, NULL, NULL, &ahc_echo, NULL,
-                      MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
-                      MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
-    curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
-    curl_easy_setopt (c, CURLOPT_POST, 1L);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-
-  return 0;
-}
-
-
-static unsigned int
-testMultithreadedPost ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD /* | 
MHD_USE_ERROR_LOG */,
-                        11080, NULL, NULL, &ahc_echo, NULL,
-                        MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
-                        MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
-    curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
-    curl_easy_setopt (c, CURLOPT_POST, 1L);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testExternalPost ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  int i;
-
-  multi = NULL;
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
-                        1082, NULL, NULL, &ahc_echo, NULL,
-                        MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
-                        MHD_OPTION_END);
-  if (d == NULL)
-    return 256;
-  multi = curl_multi_init ();
-  if (multi == NULL)
-  {
-    MHD_stop_daemon (d);
-    return 512;
-  }
-
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
-    curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
-    curl_easy_setopt (c, CURLOPT_POST, 1L);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-
-
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
-    {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
-      {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
-      }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
-      curl_easy_cleanup (c);
-    }
-
-  }
-  fprintf (stderr, "\n");
-  curl_multi_cleanup (multi);
-  zzuf_socat_stop ();
-
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  (void) argc;   /* Unused. Silent compiler warning. */
-
-  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
-           (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
-  {
-    errorCount += testInternalPost ();
-    errorCount += testMultithreadedPost ();
-  }
-  errorCount += testExternalPost ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/test_post_form.c b/src/testzzuf/test_post_form.c
deleted file mode 100644
index b16b0cdd..00000000
--- a/src/testzzuf/test_post_form.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_post_form.c
- * @brief  Testcase for libmicrohttpd POST operations using multipart/postform 
data
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-
-#include "socat.c"
-
-static int oneone;
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-
-static void
-completed_cb (void *cls,
-              struct MHD_Connection *connection,
-              void **req_cls,
-              enum MHD_RequestTerminationCode toe)
-{
-  struct MHD_PostProcessor *pp = *req_cls;
-  (void) cls; (void) connection; (void) toe;            /* Unused. Silent 
compiler warning. */
-
-  if (NULL != pp)
-    MHD_destroy_post_processor (pp);
-  *req_cls = NULL;
-}
-
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  struct CBC *cbc = ctx;
-
-  if (cbc->pos + size * nmemb > cbc->size)
-    return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
-  return size * nmemb;
-}
-
-
-/**
- * Note that this post_iterator is not perfect
- * in that it fails to support incremental processing.
- * (to be fixed in the future)
- */
-static enum MHD_Result
-post_iterator (void *cls,
-               enum MHD_ValueKind kind,
-               const char *key,
-               const char *filename,
-               const char *content_type,
-               const char *transfer_encoding,
-               const char *value, uint64_t off, size_t size)
-{
-  int *eok = cls;
-  (void) kind; (void) filename; (void) content_type; /* Unused. Silent 
compiler warning. */
-  (void) transfer_encoding; (void) off;            /* Unused. Silent compiler 
warning. */
-
-  if (key == NULL)
-    return MHD_YES;
-#if 0
-  fprintf (stderr, "PI sees %s-%.*s\n", key, size, value);
-#endif
-  if ((0 == strcmp (key, "name")) &&
-      (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
-    (*eok) |= 1;
-  if ((0 == strcmp (key, "project")) &&
-      (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
-    (*eok) |= 2;
-  return MHD_YES;
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  static int eok;
-  struct MHD_Response *response;
-  struct MHD_PostProcessor *pp;
-  enum MHD_Result ret;
-  (void) cls; (void) version;      /* Unused. Silent compiler warning. */
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp ("POST", method))
-  {
-    return MHD_NO;              /* unexpected method */
-  }
-  pp = *req_cls;
-  if (pp == NULL)
-  {
-    eok = 0;
-    pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
-    if (pp == NULL)
-      return MHD_NO;
-    *req_cls = pp;
-  }
-  MHD_post_process (pp, upload_data, *upload_data_size);
-  if ((eok == 3) && (0 == *upload_data_size))
-  {
-    response = MHD_create_response_from_buffer (strlen (url),
-                                                (void *) url,
-                                                MHD_RESPMEM_MUST_COPY);
-    ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-    MHD_destroy_response (response);
-    MHD_destroy_post_processor (pp);
-    *req_cls = NULL;
-    return ret;
-  }
-  *upload_data_size = 0;
-  return MHD_YES;
-}
-
-
-static struct curl_httppost *
-make_form ()
-{
-  struct curl_httppost *post = NULL;
-  struct curl_httppost *last = NULL;
-
-  curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
-                CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END);
-  curl_formadd (&post, &last, CURLFORM_COPYNAME, "project",
-                CURLFORM_COPYCONTENTS, "curl", CURLFORM_END);
-  return post;
-}
-
-
-static unsigned int
-testInternalPost ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-  struct curl_httppost *pd;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080, NULL, NULL, &ahc_echo, NULL,
-                      MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
-                      MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    pd = make_form ();
-    curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-    curl_formfree (pd);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testMultithreadedPost ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  int i;
-  struct curl_httppost *pd;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD /* | 
MHD_USE_ERROR_LOG */,
-                        11080, NULL, NULL, &ahc_echo, NULL,
-                        MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
-                        MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    pd = make_form ();
-    curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-    curl_formfree (pd);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testExternalPost ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  struct curl_httppost *pd;
-  int i;
-
-  multi = NULL;
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
-                        1082, NULL, NULL, &ahc_echo, NULL,
-                        MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
-                        MHD_OPTION_END);
-  if (d == NULL)
-    return 256;
-  multi = curl_multi_init ();
-  if (multi == NULL)
-  {
-    MHD_stop_daemon (d);
-    return 512;
-  }
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1082/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    pd = make_form ();
-    curl_easy_setopt (c, CURLOPT_HTTPPOST, pd);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_formfree (pd);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
-    {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        curl_formfree (pd);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        curl_formfree (pd);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
-      {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
-      }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
-      curl_easy_cleanup (c);
-    }
-    curl_formfree (pd);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  curl_multi_cleanup (multi);
-
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  (void) argc;   /* Unused. Silent compiler warning. */
-
-  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
-           (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
-  {
-    errorCount += testInternalPost ();
-    errorCount += testMultithreadedPost ();
-  }
-  errorCount += testExternalPost ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/test_put.c b/src/testzzuf/test_put.c
deleted file mode 100644
index 9e3749d1..00000000
--- a/src/testzzuf/test_put.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_put.c
- * @brief  Testcase for libmicrohttpd PUT operations
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-
-#include "socat.c"
-
-static int oneone;
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-static size_t
-putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
-{
-  unsigned int *pos = ptr;
-  unsigned int wrt;
-
-  wrt = size * nmemb;
-  if (wrt > 8 - (*pos))
-    wrt = 8 - (*pos);
-  memcpy (stream, &("Hello123"[*pos]), wrt);
-  (*pos) += wrt;
-  return wrt;
-}
-
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  struct CBC *cbc = ctx;
-
-  if (cbc->pos + size * nmemb > cbc->size)
-    return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
-  return size * nmemb;
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  int *done = cls;
-  struct MHD_Response *response;
-  enum MHD_Result ret;
-  (void) version; (void) req_cls;   /* Unused. Silent compiler warning. */
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp ("PUT", method))
-    return MHD_NO;              /* unexpected method */
-  if ((*done) == 0)
-  {
-    if (*upload_data_size != 8)
-      return MHD_YES;           /* not yet ready */
-    if (0 == memcmp (upload_data, "Hello123", 8))
-    {
-      *upload_data_size = 0;
-    }
-    else
-    {
-      printf ("Invalid upload data `%8s'!\n", upload_data);
-      return MHD_NO;
-    }
-    *done = 1;
-    return MHD_YES;
-  }
-  response = MHD_create_response_from_buffer (strlen (url),
-                                              (void *) url,
-                                              MHD_RESPMEM_MUST_COPY);
-  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-  MHD_destroy_response (response);
-  return ret;
-}
-
-
-static unsigned int
-testInternalPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080,
-                      NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testMultithreadedPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD /* | 
MHD_USE_ERROR_LOG */,
-                        11080,
-                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testExternalPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  int i;
-
-  multi = NULL;
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
-                        11080,
-                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 256;
-  multi = curl_multi_init ();
-  if (multi == NULL)
-  {
-    MHD_stop_daemon (d);
-    return 512;
-  }
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-
-
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
-    {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
-      {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
-      }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
-      curl_easy_cleanup (c);
-    }
-  }
-  fprintf (stderr, "\n");
-  curl_multi_cleanup (multi);
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  (void) argc;   /* Unused. Silent compiler warning. */
-
-  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
-           (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
-  {
-    errorCount += testInternalPut ();
-    errorCount += testMultithreadedPut ();
-  }
-  errorCount += testExternalPut ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/test_put_chunked.c b/src/testzzuf/test_put_chunked.c
deleted file mode 100644
index 3dd67e43..00000000
--- a/src/testzzuf/test_put_chunked.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file daemontest_put_chunked.c
- * @brief Testcase for libmicrohttpd PUT operations with chunked encoding
- *        for the upload data
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-#include "socat.c"
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-static size_t
-putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
-{
-  unsigned int *pos = ptr;
-  unsigned int wrt;
-
-  wrt = size * nmemb;
-  if (wrt > 8 - (*pos))
-    wrt = 8 - (*pos);
-  if (wrt > 4)
-    wrt = 4;                    /* only send half at first => force multiple 
chunks! */
-  memcpy (stream, &("Hello123"[*pos]), wrt);
-  (*pos) += wrt;
-  return wrt;
-}
-
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  struct CBC *cbc = ctx;
-
-  if (cbc->pos + size * nmemb > cbc->size)
-    return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
-  return size * nmemb;
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  int *done = cls;
-  struct MHD_Response *response;
-  enum MHD_Result ret;
-  int have;
-  (void) version; (void) req_cls;   /* Unused. Silent compiler warning. */
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp ("PUT", method))
-    return MHD_NO;              /* unexpected method */
-  if ((*done) < 8)
-  {
-    have = *upload_data_size;
-    if (have + *done > 8)
-    {
-      return MHD_NO;
-    }
-    if (0 == have)
-    {
-      (void) 0; /* Do nothing - no data yet */
-    }
-    else if (0 == memcmp (upload_data, &"Hello123"[*done], have))
-    {
-      *done += have;
-      *upload_data_size = 0;
-    }
-    else
-    {
-      return MHD_NO;
-    }
-#if 0
-    fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8);
-#endif
-    return MHD_YES;
-  }
-  response = MHD_create_response_from_buffer (strlen (url),
-                                              (void *) url,
-                                              MHD_RESPMEM_MUST_COPY);
-  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-  MHD_destroy_response (response);
-  return ret;
-}
-
-
-static unsigned int
-testInternalPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
-                        11080,
-                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    done_flag = 0;
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    /* by not giving the file size, we force chunking! */
-    /*
-       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
-     */
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testMultithreadedPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  CURLcode errornum;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
-                        11081,
-                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-  c = curl_easy_init ();
-  curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-  curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-  curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-  curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-  /* by not giving the file size, we force chunking! */
-  /*
-     curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
-   */
-  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-  curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
-  curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
-  /* NOTE: use of CONNECTTIMEOUT without also
-   *   setting NOSIGNAL results in really weird
-   *   crashes on my system! */
-  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-  if (CURLE_OK != (errornum = curl_easy_perform (c)))
-  {
-    fprintf (stderr,
-             "curl_easy_perform failed: `%s'\n",
-             curl_easy_strerror (errornum));
-    curl_easy_cleanup (c);
-    MHD_stop_daemon (d);
-    return 32;
-  }
-  curl_easy_cleanup (c);
-  MHD_stop_daemon (d);
-  if (cbc.pos != strlen ("/hello_world"))
-    return 64;
-  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
-    return 128;
-
-  return 0;
-}
-
-
-static unsigned int
-testExternalPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  char buf[2048];
-  struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  int i;
-
-  multi = NULL;
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_ERROR_LOG,
-                        11082,
-                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 256;
-
-  multi = curl_multi_init ();
-  if (multi == NULL)
-  {
-    MHD_stop_daemon (d);
-    return 512;
-  }
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-    done_flag = 0;
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11082/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    /* by not giving the file size, we force chunking! */
-    /*
-       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
-     */
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-
-
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
-    {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
-      {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
-      }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
-      curl_easy_cleanup (c);
-    }
-  }
-  fprintf (stderr, "\n");
-  curl_multi_cleanup (multi);
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  (void) argc; (void) argv; /* Unused. Silent compiler warning. */
-
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
-  {
-    errorCount += testInternalPut ();
-    errorCount += testMultithreadedPut ();
-  }
-  errorCount += testExternalPut ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/test_put_large.c b/src/testzzuf/test_put_large.c
deleted file mode 100644
index 900284ef..00000000
--- a/src/testzzuf/test_put_large.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     Copyright (C) 2007, 2008 Christian Grothoff
-
-     libmicrohttpd is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
-     option) any later version.
-
-     libmicrohttpd is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file test_put_large.c
- * @brief  Testcase for libmicrohttpd PUT operations
- * @author Christian Grothoff
- */
-
-#include "MHD_config.h"
-#include "platform.h"
-#include <curl/curl.h>
-#include <microhttpd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-#include "socat.c"
-
-static int oneone;
-
-/**
- * Do not make this much larger since we will hit the
- * MHD default buffer limit and the test code is not
- * written for incremental upload processing...
- */
-#define PUT_SIZE (256 * 1024)
-
-static char *put_buffer;
-
-struct CBC
-{
-  char *buf;
-  size_t pos;
-  size_t size;
-};
-
-static size_t
-putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
-{
-  unsigned int *pos = ptr;
-  unsigned int wrt;
-
-  wrt = size * nmemb;
-  if (wrt > PUT_SIZE - (*pos))
-    wrt = PUT_SIZE - (*pos);
-  memcpy (stream, &put_buffer[*pos], wrt);
-  (*pos) += wrt;
-  return wrt;
-}
-
-
-static size_t
-copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
-{
-  struct CBC *cbc = ctx;
-
-  if (cbc->pos + size * nmemb > cbc->size)
-    return 0;                   /* overflow */
-  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
-  cbc->pos += size * nmemb;
-  return size * nmemb;
-}
-
-
-static enum MHD_Result
-ahc_echo (void *cls,
-          struct MHD_Connection *connection,
-          const char *url,
-          const char *method,
-          const char *version,
-          const char *upload_data, size_t *upload_data_size,
-          void **req_cls)
-{
-  int *done = cls;
-  struct MHD_Response *response;
-  enum MHD_Result ret;
-  (void) version; (void) req_cls; /* Unused. Silent compiler warning. */
-
-  if (NULL == url)
-    fprintf (stderr, "The \"url\" parameter is NULL.\n");
-  if (NULL == method)
-    fprintf (stderr, "The \"method\" parameter is NULL.\n");
-  if (NULL == version)
-    fprintf (stderr, "The \"version\" parameter is NULL.\n");
-  if (NULL == upload_data_size)
-    fprintf (stderr, "The \"upload_data_size\" parameter is NULL.\n");
-  if ((0 != *upload_data_size) && (NULL == upload_data))
-    fprintf (stderr, "Upload data is NULL with non-zero size.\n");
-  if (0 != strcmp ("PUT", method))
-    return MHD_NO;              /* unexpected method */
-  if ((*done) == 0)
-  {
-    if (*upload_data_size != PUT_SIZE)
-    {
-#if 0
-      fprintf (stderr,
-               "Waiting for more data (%u/%u)...\n",
-               *upload_data_size, PUT_SIZE);
-#endif
-      return MHD_YES;           /* not yet ready */
-    }
-    if (0 == memcmp (upload_data, put_buffer, PUT_SIZE))
-    {
-      *upload_data_size = 0;
-    }
-    else
-    {
-      return MHD_NO;
-    }
-    *done = 1;
-    return MHD_YES;
-  }
-  response = MHD_create_response_from_buffer (strlen (url),
-                                              (void *) url,
-                                              MHD_RESPMEM_MUST_COPY);
-  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
-  MHD_destroy_response (response);
-  return ret;
-}
-
-
-static unsigned int
-testInternalPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  struct CBC cbc;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  char buf[2048];
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d =
-    MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD /* | MHD_USE_ERROR_LOG 
*/,
-                      11080,
-                      NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 1;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testMultithreadedPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  struct CBC cbc;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  char buf[2048];
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
-                        | MHD_USE_INTERNAL_POLLING_THREAD /* | 
MHD_USE_ERROR_LOG */,
-                        11080,
-                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
-  if (d == NULL)
-    return 16;
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_perform (c);
-    curl_easy_cleanup (c);
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-static unsigned int
-testExternalPut ()
-{
-  struct MHD_Daemon *d;
-  CURL *c;
-  struct CBC cbc;
-  CURLM *multi;
-  CURLMcode mret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  int running;
-  time_t start;
-  struct timeval tv;
-  unsigned int pos = 0;
-  int done_flag = 0;
-  char buf[2048];
-  int i;
-
-  cbc.buf = buf;
-  cbc.size = 2048;
-  cbc.pos = 0;
-  multi = NULL;
-  d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_ERROR_LOG */,
-                        11080,
-                        NULL, NULL, &ahc_echo, &done_flag,
-                        MHD_OPTION_CONNECTION_MEMORY_LIMIT,
-                        (size_t) (PUT_SIZE * 4), MHD_OPTION_END);
-  if (d == NULL)
-    return 256;
-  multi = curl_multi_init ();
-  if (multi == NULL)
-  {
-    MHD_stop_daemon (d);
-    return 512;
-  }
-  zzuf_socat_start ();
-  for (i = 0; i < LOOP_COUNT; i++)
-  {
-    fprintf (stderr, ".");
-
-    c = curl_easy_init ();
-    curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11081/hello_world";);
-    curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
-    curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
-    curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
-    curl_easy_setopt (c, CURLOPT_READDATA, &pos);
-    curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE);
-    curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
-    curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
-    if (oneone)
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
-    else
-      curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
-    curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
-    /* NOTE: use of CONNECTTIMEOUT without also
-     *   setting NOSIGNAL results in really weird
-     *   crashes on my system! */
-    curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
-
-
-    mret = curl_multi_add_handle (multi, c);
-    if (mret != CURLM_OK)
-    {
-      curl_multi_cleanup (multi);
-      curl_easy_cleanup (c);
-      zzuf_socat_stop ();
-      MHD_stop_daemon (d);
-      return 1024;
-    }
-    start = time (NULL);
-    while ((time (NULL) - start < 5) && (c != NULL))
-    {
-      max = 0;
-      FD_ZERO (&rs);
-      FD_ZERO (&ws);
-      FD_ZERO (&es);
-      curl_multi_perform (multi, &running);
-      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
-      if (mret != CURLM_OK)
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 2048;
-      }
-      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
-      {
-        curl_multi_remove_handle (multi, c);
-        curl_multi_cleanup (multi);
-        curl_easy_cleanup (c);
-        zzuf_socat_stop ();
-        MHD_stop_daemon (d);
-        return 4096;
-      }
-      tv.tv_sec = 0;
-      tv.tv_usec = 1000;
-      select (max + 1, &rs, &ws, &es, &tv);
-      curl_multi_perform (multi, &running);
-      if (running == 0)
-      {
-        curl_multi_info_read (multi, &running);
-        curl_multi_remove_handle (multi, c);
-        curl_easy_cleanup (c);
-        c = NULL;
-      }
-      MHD_run (d);
-    }
-    if (c != NULL)
-    {
-      curl_multi_remove_handle (multi, c);
-      curl_easy_cleanup (c);
-    }
-  }
-  fprintf (stderr, "\n");
-  zzuf_socat_stop ();
-  curl_multi_cleanup (multi);
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-  (void) argc; /* Unused. Silent compiler warning. */
-
-  oneone = (NULL != strrchr (argv[0], (int) '/')) ?
-           (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
-  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
-    return 2;
-  put_buffer = malloc (PUT_SIZE);
-  if (0 == put_buffer)
-    return 77;
-  memset (put_buffer, 1, PUT_SIZE);
-  if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
-  {
-    errorCount += testInternalPut ();
-    errorCount += testMultithreadedPut ();
-  }
-  errorCount += testExternalPut ();
-  free (put_buffer);
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  curl_global_cleanup ();
-  return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
-}
diff --git a/src/testzzuf/zzuf_socat_test_runner.sh 
b/src/testzzuf/zzuf_socat_test_runner.sh
new file mode 100755
index 00000000..6bc4ef37
--- /dev/null
+++ b/src/testzzuf/zzuf_socat_test_runner.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+if set -m ; then : ; else
+  echo "The shell $SHELL does not support background jobs, the test cannot 
run." 1>&2
+  exit 77
+fi
+
+socat_listen_ip='127.0.0.121'
+socat_listen_port='10121'
+mhd_listen_port='4010'
+max_runtime_sec='300'
+
+if test "x${ZZUF}" = "xno" ; then
+  echo "zzuf command missing" 1>&2
+  exit 77
+fi
+
+if command -v "${ZZUF}" > /dev/null 2>&1 ; then : ; else
+  echo "zzuf command missing" 1>&2
+  exit 77
+fi
+
+if test "x${SOCAT}" = "xno" ; then
+  echo "socat command missing" 1>&2
+  exit 77
+fi
+
+if command -v "${SOCAT}" > /dev/null 2>&1 ; then : ; else
+  echo "socat command missing" 1>&2
+  exit 77
+fi
+
+socat_test_params="-ls -lu \
+  -T0.1 -4 \
+  
TCP-LISTEN:${socat_listen_port},bind=${socat_listen_ip},reuseaddr,linger=2,linger2=1,accept-timeout=0.1
 \
+  TCP:127.0.0.1:${mhd_listen_port},reuseaddr"
+ 
+echo "## Trying to run socat to test ports availability..."
+if "${SOCAT}" ${socat_test_params} ; then
+  echo "Success."
+else
+  echo "socat test run failed" 1>&2
+  exit 77
+fi
+
+# fuzz the input only for IP ${socat_listen_ip}. libcurl uses another IP
+# in this test therefore libcurl input is not fuzzed.
+zzuf_all_params="--ratio=0.001:0.4 --autoinc --verbose --signal \
+ --max-usertime=${max_runtime_sec} --check-exit --network 
--allow=${socat_listen_ip} --exclude=."
+
+if test -n "${ZZUF_SEED}" ; then
+  zzuf_all_params="${zzuf_all_params} --seed=${ZZUF_SEED}"
+fi
+
+if test -n "${ZZUF_FLAGS}" ; then
+  zzuf_all_params="${zzuf_all_params} ${ZZUF_FLAGS}"
+fi
+
+# Uncomment the next line to see more zzuf data in logs
+#zzuf_all_params="${zzuf_all_params} -dd"
+
+socat_options="-ls -lu \
+  -T3 -4"
+socat_addr1="TCP-LISTEN:${socat_listen_port},bind=${socat_listen_ip},reuseaddr,nodelay,linger=2,linger2=1,accept-timeout=${max_runtime_sec},fork"
+socat_addr2="TCP:127.0.0.1:${mhd_listen_port},reuseaddr,connect-timeout=3,nodelay,linger=2,linger2=1"
+ 
+if test -n "${SOCAT_FLAGS}" ; then
+  socat_options="${socat_options} ${SOCAT_FLAGS}"
+fi
+
+# Uncomment the next line to see more socat data in logs
+#socat_options="${socat_options} -dd -D"
+
+# Uncomment the next line to see all traffic in logs
+#socat_options="${socat_options} -v"
+ 
+stop_zzuf_socat ()
+{
+  trap - EXIT
+  if test -n "$zzuf_pid" ; then
+    echo "The test has been interrupted." 1>&2
+    test "x$zzuf_pid" = "xstarting" && zzuf_pid=$!
+    # Finish zzuf + socat
+    kill -TERM ${zzuf_pid} -${zzuf_pid}
+    # Finish the test
+    kill -INT %2 2> /dev/null || kill -INT %1 2> /dev/null
+    exit 99
+  fi
+}
+
+echo "## Starting zzuf with socat to reflect fuzzed traffic..."
+trap 'stop_zzuf_socat' EXIT
+zzuf_pid="starting"
+"${ZZUF}" ${zzuf_all_params} "${SOCAT}" ${socat_options} ${socat_addr1} 
${socat_addr2} &
+if test $? -eq 0 ; then
+  zzuf_pid=$!
+  echo "zzuf with socat has been started."
+else
+  zzuf_pid=''
+  echo "Failed to start zzuf with socat" 1>&2
+  exit 99
+fi
+
+echo "## Starting real test of $@ with traffic fuzzed by zzuf with socat..."
+"$@" --with-socat
+test_result=$?
+trap - EXIT
+echo "$@ has exited with the return code $test_result" 
+if kill -s 0 -- $$ 2> /dev/null ; then
+  if kill -s 0 -- ${zzuf_pid} -${zzuf_pid} ; then : ; else
+    echo "No running zzuf with socat is detected after the test." 1>&2
+    echo "Looks like zzuf ended prematurely, at least part of the testing has 
not been performed." 1>&2
+    test_result=99
+  fi
+fi
+kill -TERM ${zzuf_pid} -${zzuf_pid}
+zzuf_pid=''
+exit $test_result
diff --git a/src/testzzuf/zzuf_test_runner.sh b/src/testzzuf/zzuf_test_runner.sh
new file mode 100755
index 00000000..40367639
--- /dev/null
+++ b/src/testzzuf/zzuf_test_runner.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+
+mhd_listen_ip='127.0.0.1'
+max_runtime_sec='300'
+
+if test "x${ZZUF}" = "xno" ; then
+  echo "zzuf command missing" 1>&2
+  exit 77
+fi
+
+if command -v "${ZZUF}" > /dev/null 2>&1 ; then : ; else
+  echo "zzuf command missing" 1>&2
+  exit 77
+fi
+
+run_with_socat ()
+{
+  echo "Trying to run the test with socat..."
+  script_dir=""
+  if command -v dirname > /dev/null 2>&1 ; then
+    test_dir=`dirname /`
+    if test "x${test_dir}" = "x/" ; then
+      if dirname "$1" > /dev/null 2>&1 ; then
+        script_dir=`dirname "$1"`
+        if test -n "${script_dir}" ; then
+          # Assume script is not in the root dir
+          script_dir="${script_dir}/"
+        else
+          script_dir="./"
+        fi
+      fi
+    fi
+  fi
+  if test -z "${script_dir}" ; then
+    if echo "$1" | sed 's|[^/]*$||' > /dev/null 2>&1 ; then
+      script_dir=`echo "$1" | sed 's|[^/]*$||'`
+        if test -z "${script_dir}" ; then
+          script_dir="./"
+        fi
+    fi
+  fi
+  if test -z "${script_dir}" ; then
+    echo "Cannot determine script location, will try current directory." 1>&2
+    script_dir="./"
+  fi
+  $SHELL "${script_dir}zzuf_socat_test_runner.sh" "$@"
+  exit $?
+}
+
+# zzuf cannot pass-through the return value of checked program
+# so try the direct dry-run first to get possibe 77 or 99 codes
+echo "## Dry-run of the $@..."
+if "$@" --dry-run ; then
+  echo "# Dry-run succeded."
+else
+  res_code=$?
+  echo "Dry-run failed with exit code $res_code." 1>&2
+  if test $res_code -ne 99; then
+    run_with_socat "$@"
+  fi
+  echo "$@ will not be run with zzuf." 1>&2
+  exit $res_code
+fi
+
+# fuzz the input only for IP ${mhd_listen_ip}. libcurl uses another IP
+# in this test therefore libcurl input is not fuzzed.
+zzuf_all_params="--ratio=0.001:0.4 --autoinc --verbose --signal \
+ --max-usertime=${max_runtime_sec} --check-exit --network \
+ --allow=${mhd_listen_ip} --exclude=."
+
+if test -n "${ZZUF_SEED}" ; then
+  zzuf_all_params="${zzuf_all_params} --seed=${ZZUF_SEED}"
+fi
+
+if test -n "${ZZUF_FLAGS}" ; then
+  zzuf_all_params="${zzuf_all_params} ${ZZUF_FLAGS}"
+fi
+
+# Uncomment the next line to see more data in logs
+#zzuf_all_params="${zzuf_all_params} -dd"
+
+echo "## Dry-run of the $@ with zzuf..."
+if "$ZZUF" ${zzuf_all_params} "$@" --dry-run ; then
+  echo "# Dry-run with zzuf succeded."
+else
+  res_code=$?
+  echo "$@ cannot be run with zzuf directly." 1>&2
+  run_with_socat "$@"
+  exit $res_code
+fi
+
+echo "## Real test of $@ with zzuf..."
+"$ZZUF" ${zzuf_all_params} "$@"
+exit $?
diff --git a/w32/common/cpp.hint b/w32/common/cpp.hint
new file mode 100644
index 00000000..f41fbbde
--- /dev/null
+++ b/w32/common/cpp.hint
@@ -0,0 +1,3 @@
+/* This is a helper file used by MSVC Browsing Database Parser.
+   This file is required to quickly identify functions in the code. */
+#define _MHD_EXTERN
diff --git a/w32/common/libmicrohttpd-files.vcxproj 
b/w32/common/libmicrohttpd-files.vcxproj
index 0790a3eb..8f719f06 100644
--- a/w32/common/libmicrohttpd-files.vcxproj
+++ b/w32/common/libmicrohttpd-files.vcxproj
@@ -81,4 +81,7 @@
       
<AdditionalInputs>$(MhdW32Common)gen_dll_res.ps1;$(MhdRoot)configure.ac</AdditionalInputs>
     </CustomBuild>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="$(MhdW32Common)cpp.hint" />
+  </ItemGroup>
 </Project>
diff --git a/w32/common/libmicrohttpd-filters.vcxproj 
b/w32/common/libmicrohttpd-filters.vcxproj
index 27fd6f18..f0dfd0d9 100644
--- a/w32/common/libmicrohttpd-filters.vcxproj
+++ b/w32/common/libmicrohttpd-filters.vcxproj
@@ -215,4 +215,7 @@
       <Filter>Template Files</Filter>
     </CustomBuild>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="$(MhdW32Common)cpp.hint" />
+  </ItemGroup>
 </Project>

-- 
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]