gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (5e0c2223 -> 9f4a08a8)


From: gnunet
Subject: [libmicrohttpd] branch master updated (5e0c2223 -> 9f4a08a8)
Date: Fri, 28 Oct 2022 11:21:49 +0200

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 5e0c2223 Fixed builds with old compilers after 
0b9776811f2d8bd1041b759bd84733754bba7b3e
     new 30beb61e Added ability to check for MHD debug builds at run-time
     new cf6f91bd Added check for hypothetical too large accepted sockets 
addresses
     new 571ec180 New values for MHD_ConnectionEventLoopInfo
     new 699b6cd5 Added new state for MHD_ConnectionEventLoopInfo
     new 9fef2196 Renamed one state in MHD_ConnectionEventLoopInfo for clarity
     new dd7f9dfe Renamed one more connection state for clarity
     new 692e8c56 Do not send "100 Continue" if request does not have a body
     new bf9e9972 Do not send "100 Continue" if part of the request body is 
already received
     new f1c69db3 Reworked partial processing of the upload
     new f1bfbe71 connection.c: fixed handling of various errors automatically 
detected by MHD code
     new 9b86ff30 testcurl: added test with Content-Length broken value in 
request
     new b44b4f73 test_head: added check for excess data in reply
     new f5d7b2fc test_head: check libcurl for timeout value
     new 89e73e62 postprocessor.h: fixed typos in doxy
     new 9f4a08a8 microhttpd.h: doxy improvements

The 15 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:
 src/include/microhttpd.h                           |  27 ++-
 src/microhttpd/connection.c                        | 120 ++++++----
 src/microhttpd/daemon.c                            | 124 +++++++----
 src/microhttpd/internal.c                          |   6 +-
 src/microhttpd/internal.h                          |  31 ++-
 src/microhttpd/postprocessor.h                     |   8 +-
 src/testcurl/Makefile.am                           |   7 +
 src/testcurl/test_head.c                           |  61 ++++-
 .../{test_head.c => test_put_broken_len.c}         | 245 +++++++--------------
 9 files changed, 363 insertions(+), 266 deletions(-)
 copy src/testcurl/{test_head.c => test_put_broken_len.c} (75%)

diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 13bfa554..0eae3f9f 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 0x00097542
+#define MHD_VERSION 0x00097543
 
 /* If generic headers don't work on your platform, include headers
    which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -1560,12 +1560,12 @@ enum MHD_DAuthBindNonce
    * expired yet.
    * It is recommended because RFC 7616 allows clients to use the same nonce
    * for any request in the same "protection space".
-   * CPU is loaded less when this value is used when checking client's
-   * authorisation requests.
+   * When checking client's authorisation requests CPU is loaded less if this
+   * value is used.
    * This mode gives MHD maximum flexibility for nonces generation and can
    * prevent possible nonce collisions (and corresponding log warning messages)
    * when clients' requests are intensive.
-   * This value cannot be combined with other values.
+   * This value cannot be biwise-OR combined with other values.
    */
   MHD_DAUTH_BIND_NONCE_NONE = 0,
 
@@ -1579,10 +1579,10 @@ enum MHD_DAuthBindNonce
    * after '?' in URI) and request method (GET, POST etc).
    * Not recommended unless "protection space" is limited to a single URI as
    * RFC 7616 allows clients to re-use server-generated nonces for any URI
-   * in the same "protection space" which is by default consists of all server
+   * in the same "protection space" which by default consists of all server
    * URIs.
-   * This was default (and only supported) nonce bind type
-   * before #MHD_VERSION 0x00097518
+   * Before #MHD_VERSION 0x00097518 this was default (and only supported)
+   * nonce bind type.
    */
   MHD_DAUTH_BIND_NONCE_URI = 1 << 1,
 
@@ -2735,7 +2735,8 @@ typedef void
  *
  * @param cls user-specified closure
  * @param kind type of the value, always #MHD_POSTDATA_KIND when called from 
MHD
- * @param key 0-terminated key for the value
+ * @param key 0-terminated key for the value, NULL if not known. This value
+ *            is never NULL for url-encoded POST data.
  * @param filename name of the uploaded file, NULL if not known
  * @param content_type mime-type of the data, NULL if not known
  * @param transfer_encoding encoding of the data, NULL if not known
@@ -6186,7 +6187,15 @@ enum MHD_FEATURE
    * unlikely.
    * @note Available since #MHD_VERSION 0x00097540
    */
-  MHD_FEATURE_EXTERN_HASH = 32
+  MHD_FEATURE_EXTERN_HASH = 32,
+
+  /**
+   * Get whether MHD was built with asserts enabled.
+   * For debug builds the error log is always enabled even if 
#MHD_USE_ERROR_LOG
+   * is not specified for daemon.
+   * @note Available since #MHD_VERSION 0x00097543
+   */
+  MHD_FEATURE_DEBUG_BUILD = 33
 };
 
 
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 30260402..798052da 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -765,17 +765,27 @@ need_100_continue (struct MHD_Connection *connection)
 {
   const char *expect;
 
-  return (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver) &&
-          (MHD_NO !=
-           MHD_lookup_connection_value_n (connection,
-                                          MHD_HEADER_KIND,
-                                          MHD_HTTP_HEADER_EXPECT,
-                                          MHD_STATICSTR_LEN_ (
-                                            MHD_HTTP_HEADER_EXPECT),
-                                          &expect,
-                                          NULL)) &&
-          (MHD_str_equal_caseless_ (expect,
-                                    "100-continue")) );
+  if (! MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver))
+    return false;
+
+  if (0 == connection->rq.remaining_upload_size)
+    return false;
+
+  if (MHD_NO ==
+      MHD_lookup_connection_value_n (connection,
+                                     MHD_HEADER_KIND,
+                                     MHD_HTTP_HEADER_EXPECT,
+                                     MHD_STATICSTR_LEN_ ( \
+                                       MHD_HTTP_HEADER_EXPECT),
+                                     &expect,
+                                     NULL))
+    return false;
+
+  if (MHD_str_equal_caseless_ (expect,
+                               "100-continue"))
+    return true;
+
+  return false;
 }
 
 
@@ -2543,7 +2553,7 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
       if (! connection->discard_request)
         connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
       else
-        connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+        connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
       break;
     case MHD_CONNECTION_HEADERS_RECEIVED:
       mhd_assert (0);
@@ -2554,7 +2564,7 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
     case MHD_CONNECTION_CONTINUE_SENDING:
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
       break;
-    case MHD_CONNECTION_CONTINUE_SENT:
+    case MHD_CONNECTION_BODY_RECEIVING:
       if (connection->read_buffer_offset == connection->read_buffer_size)
       {
         const bool internal_poll = (0 != (connection->daemon->options
@@ -2582,8 +2592,10 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
       if ( (connection->read_buffer_offset < connection->read_buffer_size) &&
            (! connection->discard_request) )
         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_BLOCK;
+        connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
       break;
     case MHD_CONNECTION_BODY_RECEIVED:
     case MHD_CONNECTION_FOOTER_PART_RECEIVED:
@@ -2603,7 +2615,7 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
       mhd_assert (0);
       break;
     case MHD_CONNECTION_FULL_REQ_RECEIVED:
-      connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+      connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
       break;
     case MHD_CONNECTION_START_REPLY:
       mhd_assert (0);
@@ -2619,13 +2631,13 @@ MHD_connection_update_event_loop_info (struct 
MHD_Connection *connection)
       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
       break;
     case MHD_CONNECTION_NORMAL_BODY_UNREADY:
-      connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+      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_UNREADY:
-      connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
+      connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
       break;
     case MHD_CONNECTION_CHUNKED_BODY_SENT:
       mhd_assert (0);
@@ -3438,6 +3450,8 @@ 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
@@ -3663,19 +3677,27 @@ 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;
     if (0 != left_unprocessed)
     {
       instant_retry = false; /* client did not process everything */
 #ifdef HAVE_MESSAGES
-      /* client did not process all upload data, complain if
-         the setup was incorrect, which may prevent us from
-         handling the rest of the request */
-      if ( (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
-           (! connection->suspended) )
-        MHD_DLOG (daemon,
-                  _ ("WARNING: incomplete upload processing and connection " \
-                     "not suspended may result in hung connection.\n"));
-#endif
+      if ((left_unprocessed == to_be_processed) &&
+          (! connection->suspended))
+      {
+        /* client did not process any upload data, complain if
+           the setup was incorrect, which may prevent us from
+           handling the rest of the request */
+        if (0 != (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD))
+          MHD_DLOG (daemon,
+                    _ ("WARNING: Access Handler Callback has not processed " \
+                       "any upload data and connection is not suspended. " \
+                       "This may result in hung connection.\n"));
+      }
+#endif /* HAVE_MESSAGES */
     }
     processed_size = to_be_processed - left_unprocessed;
     if (connection->rq.have_chunked_upload)
@@ -4173,7 +4195,7 @@ MHD_connection_handle_read (struct MHD_Connection 
*connection,
   case MHD_CONNECTION_HEADERS_RECEIVED:
   case MHD_CONNECTION_HEADERS_PROCESSED:
   case MHD_CONNECTION_CONTINUE_SENDING:
-  case MHD_CONNECTION_CONTINUE_SENT:
+  case MHD_CONNECTION_BODY_RECEIVING:
   case MHD_CONNECTION_BODY_RECEIVED:
   case MHD_CONNECTION_FOOTER_PART_RECEIVED:
   case MHD_CONNECTION_FOOTERS_RECEIVED:
@@ -4297,7 +4319,7 @@ MHD_connection_handle_write (struct MHD_Connection 
*connection)
     connection->continue_message_write_offset += (size_t) ret;
     MHD_update_last_activity_ (connection);
     return;
-  case MHD_CONNECTION_CONTINUE_SENT:
+  case MHD_CONNECTION_BODY_RECEIVING:
   case MHD_CONNECTION_BODY_RECEIVED:
   case MHD_CONNECTION_FOOTER_PART_RECEIVED:
   case MHD_CONNECTION_FOOTERS_RECEIVED:
@@ -4741,6 +4763,7 @@ 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;
 
     memset (&c->rq, 0, sizeof(c->rq));
 
@@ -4819,6 +4842,8 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     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
@@ -4853,10 +4878,10 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     case MHD_CONNECTION_URL_RECEIVED:
       line = get_next_header_line (connection,
                                    NULL);
+      if (MHD_CONNECTION_URL_RECEIVED != connection->state)
+        continue;
       if (NULL == line)
       {
-        if (MHD_CONNECTION_URL_RECEIVED != connection->state)
-          continue;
         if (connection->read_closed)
         {
           CONNECTION_CLOSE_ERROR (connection,
@@ -4885,6 +4910,8 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     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)
@@ -4912,7 +4939,7 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       continue;
     case MHD_CONNECTION_HEADERS_RECEIVED:
       parse_connection_headers (connection);
-      if (MHD_CONNECTION_CLOSED == connection->state)
+      if (MHD_CONNECTION_HEADERS_RECEIVED != connection->state)
         continue;
       connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
       if (connection->suspended)
@@ -4920,12 +4947,16 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       continue;
     case MHD_CONNECTION_HEADERS_PROCESSED:
       call_connection_handler (connection);     /* first call */
-      if (MHD_CONNECTION_CLOSED == connection->state)
+      if (MHD_CONNECTION_HEADERS_PROCESSED != connection->state)
         continue;
       if (connection->suspended)
         continue;
+
       if ( (NULL == connection->rp.response) &&
-           (need_100_continue (connection)) )
+           (need_100_continue (connection)) &&
+           /* If the client is already sending the payload (body)
+              there is no need to send "100 Continue" */
+           (0 == connection->read_buffer_offset) )
       {
         connection->state = MHD_CONNECTION_CONTINUE_SENDING;
         break;
@@ -4940,7 +4971,7 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       }
       connection->state = (0 == connection->rq.remaining_upload_size)
                           ? MHD_CONNECTION_FULL_REQ_RECEIVED
-                          : MHD_CONNECTION_CONTINUE_SENT;
+                          : MHD_CONNECTION_BODY_RECEIVING;
       if (connection->suspended)
         break;
       continue;
@@ -4948,19 +4979,16 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       if (connection->continue_message_write_offset ==
           MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE))
       {
-        connection->state = MHD_CONNECTION_CONTINUE_SENT;
+        connection->state = MHD_CONNECTION_BODY_RECEIVING;
         continue;
       }
       break;
-    case MHD_CONNECTION_CONTINUE_SENT:
+    case MHD_CONNECTION_BODY_RECEIVING:
       if (0 != connection->read_buffer_offset)
       {
         process_request_body (connection);           /* loop call */
-        if (connection->discard_request)
-        {
-          mhd_assert (MHD_CONNECTION_CONTINUE_SENT != connection->state);
+        if (MHD_CONNECTION_BODY_RECEIVING != connection->state)
           continue;
-        }
       }
       if ( (0 == connection->rq.remaining_upload_size) ||
            ( (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size) &&
@@ -4980,10 +5008,10 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     case MHD_CONNECTION_BODY_RECEIVED:
       line = get_next_header_line (connection,
                                    NULL);
+      if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
+        continue;
       if (NULL == line)
       {
-        if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
-          continue;
         if (connection->read_closed)
         {
           CONNECTION_CLOSE_ERROR (connection,
@@ -5014,10 +5042,10 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     case MHD_CONNECTION_FOOTER_PART_RECEIVED:
       line = get_next_header_line (connection,
                                    NULL);
+      if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
+        continue;
       if (NULL == line)
       {
-        if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
-          continue;
         if (connection->read_closed)
         {
           CONNECTION_CLOSE_ERROR (connection,
@@ -5046,7 +5074,7 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       continue;
     case MHD_CONNECTION_FULL_REQ_RECEIVED:
       call_connection_handler (connection);     /* "final" call */
-      if (connection->state == MHD_CONNECTION_CLOSED)
+      if (connection->state != MHD_CONNECTION_FULL_REQ_RECEIVED)
         continue;
       if (NULL == connection->rp.response)
         break;                  /* try again next time */
@@ -5277,7 +5305,7 @@ MHD_connection_epoll_update_ (struct MHD_Connection 
*connection)
        (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
        ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) &&
            (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
-         ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) &&
+         ( (0 != (MHD_EVENT_LOOP_INFO_READ & connection->event_loop_info)) &&
            (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
   {
     /* add to epoll set */
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 90a49e91..2d6df1a2 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -985,6 +985,7 @@ internal_get_fdset2 (struct MHD_Daemon *daemon,
     switch (pos->event_loop_info)
     {
     case MHD_EVENT_LOOP_INFO_READ:
+    case MHD_EVENT_LOOP_INFO_PROCESS_READ:
       if (! MHD_add_to_fd_set_ (pos->socket_fd,
                                 read_fd_set,
                                 max_fd,
@@ -1010,7 +1011,7 @@ internal_get_fdset2 (struct MHD_Daemon *daemon,
                           fd_setsize);
 #endif /* MHD_POSIX_SOCKETS */
       break;
-    case MHD_EVENT_LOOP_INFO_BLOCK:
+    case MHD_EVENT_LOOP_INFO_PROCESS:
       if ( (NULL == except_fd_set) ||
            ! MHD_add_to_fd_set_ (pos->socket_fd,
                                  except_fd_set,
@@ -1181,7 +1182,7 @@ call_handlers (struct MHD_Connection *con,
   if (con->tls_read_ready)
     read_ready = true;
 #endif /* HTTPS_SUPPORT */
-  if ( (MHD_EVENT_LOOP_INFO_READ == con->event_loop_info) &&
+  if ( (0 != (MHD_EVENT_LOOP_INFO_READ & con->event_loop_info)) &&
        (read_ready || (force_close && con->sk_nonblck)) )
   {
     MHD_connection_handle_read (con, force_close);
@@ -1255,11 +1256,11 @@ call_handlers (struct MHD_Connection *con,
   if ( (! con->daemon->data_already_pending) &&
        (0 == (con->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) )
   {
-    if (MHD_EVENT_LOOP_INFO_BLOCK == con->event_loop_info)
+    if (0 != (MHD_EVENT_LOOP_INFO_PROCESS & con->event_loop_info))
       con->daemon->data_already_pending = true;
 #ifdef HTTPS_SUPPORT
     else if ( (con->tls_read_ready) &&
-              (MHD_EVENT_LOOP_INFO_READ == con->event_loop_info) )
+              (0 != (MHD_EVENT_LOOP_INFO_READ & con->event_loop_info)) )
       con->daemon->data_already_pending = true;
 #endif /* HTTPS_SUPPORT */
   }
@@ -1985,13 +1986,13 @@ thread_main_handle_connection (void *data)
       was_suspended = false;
     }
 
-    use_zero_timeout = ( (MHD_EVENT_LOOP_INFO_BLOCK == con->event_loop_info)
+    use_zero_timeout =
+      (0 != (MHD_EVENT_LOOP_INFO_PROCESS & con->event_loop_info)
 #ifdef HTTPS_SUPPORT
-                         || ( (con->tls_read_ready) && \
-                              (MHD_EVENT_LOOP_INFO_READ ==
-                               con->event_loop_info) )
+       || ( (con->tls_read_ready) &&
+            (0 != (MHD_EVENT_LOOP_INFO_READ & con->event_loop_info)) )
 #endif /* HTTPS_SUPPORT */
-                         );
+      );
     if (! use_poll)
     {
       /* use select */
@@ -2027,6 +2028,7 @@ thread_main_handle_connection (void *data)
       switch (con->event_loop_info)
       {
       case MHD_EVENT_LOOP_INFO_READ:
+      case MHD_EVENT_LOOP_INFO_PROCESS_READ:
         if (! MHD_add_to_fd_set_ (con->socket_fd,
                                   &rs,
                                   &maxsock,
@@ -2040,7 +2042,7 @@ thread_main_handle_connection (void *data)
                                   FD_SETSIZE))
           err_state = true;
         break;
-      case MHD_EVENT_LOOP_INFO_BLOCK:
+      case MHD_EVENT_LOOP_INFO_PROCESS:
         if (! MHD_add_to_fd_set_ (con->socket_fd,
                                   &es,
                                   &maxsock,
@@ -2133,12 +2135,13 @@ thread_main_handle_connection (void *data)
       switch (con->event_loop_info)
       {
       case MHD_EVENT_LOOP_INFO_READ:
+      case MHD_EVENT_LOOP_INFO_PROCESS_READ:
         p[0].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC;
         break;
       case MHD_EVENT_LOOP_INFO_WRITE:
         p[0].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC;
         break;
-      case MHD_EVENT_LOOP_INFO_BLOCK:
+      case MHD_EVENT_LOOP_INFO_PROCESS:
         p[0].events |= MHD_POLL_EVENTS_ERR_DISC;
         break;
       case MHD_EVENT_LOOP_INFO_CLEANUP:
@@ -2530,6 +2533,7 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
   connection->sk_spipe_suppress = sk_spipe_supprs;
   connection->daemon = daemon;
   connection->connection_timeout_ms = daemon->connection_timeout_ms;
+  connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   if (0 != connection->connection_timeout_ms)
     connection->last_activity = MHD_monotonic_msec_counter ();
 
@@ -3656,6 +3660,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
   bool sk_nonbl;
   bool sk_spipe_supprs;
   bool sk_cloexec;
+  enum MHD_tristate sk_non_ip;
 
 #ifdef MHD_USE_THREADS
   mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
@@ -3675,37 +3680,48 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
   addrstorage.ss_len = addrlen;
 #endif /* HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */
 
+  /* Initialise with default values to avoid compiler warnings */
+  sk_nonbl = false;
+  sk_spipe_supprs = false;
+  sk_cloexec = false;
+
 #ifdef USE_ACCEPT4
-  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);
+  if (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
-  sk_spipe_supprs = (SOCK_NOSIGPIPE_OR_ZERO != 0);
+    sk_spipe_supprs = (SOCK_NOSIGPIPE_OR_ZERO != 0);
 #else  /* MHD_WINSOCK_SOCKETS */
-  sk_spipe_supprs = true; /* Nothing to suppress on W32 */
+    sk_spipe_supprs = true; /* Nothing to suppress on W32 */
 #endif /* MHD_WINSOCK_SOCKETS */
-  sk_cloexec = (SOCK_CLOEXEC_OR_ZERO != 0);
+    sk_cloexec = (SOCK_CLOEXEC_OR_ZERO != 0);
+  }
 #else  /* ! USE_ACCEPT4 */
-  s = accept (fd,
-              (struct sockaddr *) &addrstorage,
-              &addrlen);
+  if (MHD_INVALID_SOCKET !=
+      (s = accept (fd,
+                   (struct sockaddr *) &addrstorage,
+                   &addrlen)))
+  {
 #ifdef MHD_ACCEPT_INHERIT_NONBLOCK
-  sk_nonbl = daemon->listen_nonblk;
+    sk_nonbl = daemon->listen_nonblk;
 #else  /* ! MHD_ACCEPT_INHERIT_NONBLOCK */
-  sk_nonbl = false;
+    sk_nonbl = false;
 #endif /* ! MHD_ACCEPT_INHERIT_NONBLOCK */
 #ifndef MHD_WINSOCK_SOCKETS
-  sk_spipe_supprs = false;
+    sk_spipe_supprs = false;
 #else  /* MHD_WINSOCK_SOCKETS */
-  sk_spipe_supprs = true; /* Nothing to suppress on W32 */
+    sk_spipe_supprs = true; /* Nothing to suppress on W32 */
 #endif /* MHD_WINSOCK_SOCKETS */
-  sk_cloexec = false;
+    sk_cloexec = false;
+  }
 #endif /* ! USE_ACCEPT4 */
-  if ( (MHD_INVALID_SOCKET == s) ||
-       (addrlen <= 0) )
+
+  if (MHD_INVALID_SOCKET == s)
   {
     const int err = MHD_socket_get_error_ ();
 
@@ -3721,10 +3737,6 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
                 _ ("Error accepting connection: %s\n"),
                 MHD_socket_strerr_ (err));
 #endif
-    if (MHD_INVALID_SOCKET != s)
-    {
-      MHD_socket_close_chk_ (s);
-    }
     if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err) )
     {
       /* system/process out of resources */
@@ -3762,6 +3774,35 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
     return MHD_NO;
   }
 
+  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,
+                _ ("Accepted socket has zero-length address. "
+                   "Processing the new socket as a socket with " \
+                   "unknown type.\n"));
+#endif
+    addrlen = 0;
+    sk_non_ip = _MHD_YES; /* IP-type addresses have non-zero length */
+  }
+  if (((socklen_t) sizeof (addrstorage)) < addrlen)
+  {
+    /* Should not happen as 'sockaddr_storage' must be large enough to
+     * store any address supported by the system. */
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _ ("Accepted socket address is larger than expected by " \
+                 "system headers. Processing the new socket as a socket with " 
\
+                 "unknown type.\n"));
+#endif
+    addrlen = 0;
+    sk_non_ip = _MHD_YES; /* IP-type addresses must fit */
+  }
+
   if (! sk_nonbl && ! MHD_socket_nonblocking_ (s))
   {
 #ifdef HAVE_MESSAGES
@@ -3825,7 +3866,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
                                   false,
                                   sk_nonbl,
                                   sk_spipe_supprs,
-                                  daemon->listen_is_unix);
+                                  sk_non_ip);
   return MHD_YES;
 }
 
@@ -4712,12 +4753,13 @@ MHD_poll_all (struct MHD_Daemon *daemon,
       switch (pos->event_loop_info)
       {
       case MHD_EVENT_LOOP_INFO_READ:
+      case MHD_EVENT_LOOP_INFO_PROCESS_READ:
         p[poll_server + i].events |= POLLIN | MHD_POLL_EVENTS_ERR_DISC;
         break;
       case MHD_EVENT_LOOP_INFO_WRITE:
         p[poll_server + i].events |= POLLOUT | MHD_POLL_EVENTS_ERR_DISC;
         break;
-      case MHD_EVENT_LOOP_INFO_BLOCK:
+      case MHD_EVENT_LOOP_INFO_PROCESS:
         p[poll_server + i].events |=  MHD_POLL_EVENTS_ERR_DISC;
         break;
       case MHD_EVENT_LOOP_INFO_CLEANUP:
@@ -5324,7 +5366,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
         if (0 != (events[i].events & EPOLLIN))
         {
           pos->epoll_state |= MHD_EPOLL_STATE_READ_READY;
-          if ( ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) ||
+          if ( ( (0 != (MHD_EVENT_LOOP_INFO_READ & pos->event_loop_info)) ||
                  (pos->read_buffer_size > pos->read_buffer_offset) ) &&
                (0 == (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
           {
@@ -5414,7 +5456,7 @@ MHD_epoll (struct MHD_Daemon *daemon,
         (pos->epoll_state & (MHD_EPOLL_STATE_SUSPENDED
                              | MHD_EPOLL_STATE_IN_EREADY_EDLL)))
     {
-      if ( ((MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) &&
+      if ( ((0 != (MHD_EVENT_LOOP_INFO_READ & pos->event_loop_info)) &&
             (0 == (pos->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ||
            ((MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) &&
             (0 == (pos->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) ) ||
@@ -8747,6 +8789,12 @@ MHD_is_feature_supported (enum MHD_FEATURE feature)
 #else
     return MHD_NO;
 #endif
+  case MHD_FEATURE_DEBUG_BUILD:
+#ifdef _DEBUG
+    return MHD_YES;
+#else
+    return MHD_NO;
+#endif
 
   default:
     break;
diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c
index dee21e9e..6f80b984 100644
--- a/src/microhttpd/internal.c
+++ b/src/microhttpd/internal.c
@@ -1,6 +1,7 @@
 /*
      This file is part of libmicrohttpd
      Copyright (C) 2007 Daniel Pittman and Christian Grothoff
+     Copyright (C) 2015-2021 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
@@ -22,6 +23,7 @@
  * @brief  internal shared structures
  * @author Daniel Pittman
  * @author Christian Grothoff
+ * @author Karlson2k (Evgeny Grin)
  */
 
 #include "internal.h"
@@ -51,8 +53,8 @@ MHD_state_to_string (enum MHD_CONNECTION_STATE state)
     return "headers processed";
   case MHD_CONNECTION_CONTINUE_SENDING:
     return "continue sending";
-  case MHD_CONNECTION_CONTINUE_SENT:
-    return "continue sent";
+  case MHD_CONNECTION_BODY_RECEIVING:
+    return "body receiving";
   case MHD_CONNECTION_BODY_RECEIVED:
     return "body received";
   case MHD_CONNECTION_FOOTER_PART_RECEIVED:
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 6a88177e..78481b21 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -214,22 +214,29 @@ enum MHD_ConnectionEventLoopInfo
   /**
    * We are waiting to be able to read.
    */
-  MHD_EVENT_LOOP_INFO_READ = 0,
+  MHD_EVENT_LOOP_INFO_READ = 1 << 0,
 
   /**
    * We are waiting to be able to write.
    */
-  MHD_EVENT_LOOP_INFO_WRITE = 1,
+  MHD_EVENT_LOOP_INFO_WRITE = 1 << 1,
 
   /**
    * We are waiting for the application to provide data.
    */
-  MHD_EVENT_LOOP_INFO_BLOCK = 2,
+  MHD_EVENT_LOOP_INFO_PROCESS = 1 << 2,
+
+  /**
+   * Some data is ready to be processed, but more data could
+   * be read.
+   */
+  MHD_EVENT_LOOP_INFO_PROCESS_READ =
+    MHD_EVENT_LOOP_INFO_READ | MHD_EVENT_LOOP_INFO_PROCESS,
 
   /**
    * We are finished and are awaiting cleanup.
    */
-  MHD_EVENT_LOOP_INFO_CLEANUP = 3
+  MHD_EVENT_LOOP_INFO_CLEANUP = 1 << 3
 } _MHD_FIXED_ENUM;
 
 
@@ -642,12 +649,12 @@ enum MHD_CONNECTION_STATE
   /**
    * We have sent 100 CONTINUE (or do not need to).  Read the message body.
    */
-  MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
+  MHD_CONNECTION_BODY_RECEIVING = MHD_CONNECTION_CONTINUE_SENDING + 1,
 
   /**
    * We got the request body.  Wait for a line of the footer.
    */
-  MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
+  MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_BODY_RECEIVING + 1,
 
   /**
    * We got part of a line of the footer.  Wait for the
@@ -1014,6 +1021,18 @@ 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.
+   * 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.
+   * 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).
+   */
+  bool some_payload_processed;
+
   /**
    * We allow the main application to associate some pointer with the
    * HTTP request, which is passed to each #MHD_AccessHandlerCallback
diff --git a/src/microhttpd/postprocessor.h b/src/microhttpd/postprocessor.h
index df681ce9..c3b19ef1 100644
--- a/src/microhttpd/postprocessor.h
+++ b/src/microhttpd/postprocessor.h
@@ -74,13 +74,13 @@ enum RN_State
   RN_OptN = 1,
 
   /**
-   * Expect LFCR (and only LFCR).  As always, we also
+   * Expect CRLF (and only CRLF).  As always, we also
    * expect only LF or only CR.
    */
   RN_Full = 2,
 
   /**
-   * Expect either LFCR or '--'LFCR.  If '--'LFCR, transition into dash-state
+   * Expect either CRLF or '--'CRLF.  If '--'CRLF, transition into dash-state
    * for the main state machine
    */
   RN_Dash = 3,
@@ -222,9 +222,9 @@ struct MHD_PostProcessor
   enum PP_State state;
 
   /**
-   * Side-state-machine: skip LRCR (or just LF).
+   * Side-state-machine: skip CRLF (or just LF).
    * Set to 0 if we are not in skip mode.  Set to 2
-   * if a LFCR is expected, set to 1 if a CR should
+   * if a CRLF is expected, set to 1 if a CR should
    * be skipped if it is the next character.
    */
   enum RN_State skip_rn;
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index 13f9fed7..11a489c3 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -114,6 +114,8 @@ check_PROGRAMS = \
   test_put11 \
   test_large_put11 \
   test_large_put_inc11 \
+  test_put_broken_len10 \
+  test_put_broken_len \
   test_get_chunked \
   test_get_chunked_close \
   test_get_chunked_string \
@@ -607,3 +609,8 @@ test_tricky_url_SOURCES = \
 
 test_tricky_header2_SOURCES = \
   test_tricky.c mhd_has_in_name.h mhd_has_param.h
+
+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)
diff --git a/src/testcurl/test_head.c b/src/testcurl/test_head.c
index 6ce78217..3c984125 100644
--- a/src/testcurl/test_head.c
+++ b/src/testcurl/test_head.c
@@ -434,6 +434,54 @@ setCURL_rq_path (CURL *c, int uri_exist)
 }
 
 
+static int
+libcurl_debug_cb (CURL *handle,
+                  curl_infotype type,
+                  char *data,
+                  size_t size,
+                  void *userptr)
+{
+  static const char excess_mark[] = "Excess found";
+  static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
+
+  (void) handle;
+  (void) userptr;
+
+#ifdef _DEBUG
+  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:
+#if 0
+    fprintf (stderr, "<| %.*s\n", (int) size, data);
+#endif
+    break;
+  case CURLINFO_DATA_OUT:
+  case CURLINFO_SSL_DATA_IN:
+  case CURLINFO_SSL_DATA_OUT:
+  case CURLINFO_END:
+  default:
+    break;
+  }
+#endif /* _DEBUG */
+  if (CURLINFO_TEXT == type)
+  {
+    if ((size >= excess_mark_len) &&
+        (0 == memcmp (data, excess_mark, excess_mark_len)))
+      mhdErrorExitDesc ("Extra data has been detected in MHD reply");
+  }
+  return 0;
+}
+
+
 static CURL *
 setupCURL (void *cbc, uint16_t port,
            struct headers_check_result *hdr_chk_result)
@@ -466,6 +514,8 @@ setupCURL (void *cbc, uint16_t port,
 #ifdef _DEBUG
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
 #endif /* _DEBUG */
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
+                                     &libcurl_debug_cb)) ||
 #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) */
@@ -562,6 +612,15 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
       mhdErrorExitDesc ("MHD_get_fdset() failed");
     tv.tv_sec = 0;
     tv.tv_usec = 200000;
+    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;
+    }
 #ifdef MHD_POSIX_SOCKETS
     if (maxMhdSk > maxCurlSk)
       maxCurlSk = maxMhdSk;
@@ -575,7 +634,7 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
       if ((WSAEINVAL != WSAGetLastError ()) ||
           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
         externalErrorExitDesc ("Unexpected select() error");
-      Sleep (200);
+      Sleep ((unsigned long) tv.tv_usec / 1000);
 #endif
     }
     if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
diff --git a/src/testcurl/test_head.c b/src/testcurl/test_put_broken_len.c
similarity index 75%
copy from src/testcurl/test_head.c
copy to src/testcurl/test_put_broken_len.c
index 6ce78217..18e22e2d 100644
--- a/src/testcurl/test_head.c
+++ b/src/testcurl/test_put_broken_len.c
@@ -21,7 +21,7 @@
 
 /**
  * @file testcurl/test_head.c
- * @brief  Testcase for HEAD requests
+ * @brief  Testcase for PUT requests with broken Content-Length header
  * @author Karlson2k (Evgeny Grin)
  */
 
@@ -190,7 +190,7 @@ _mhdErrorExit_func (const char *errDesc, const char 
*funcName, int lineNum)
 
 
 /* Could be increased to facilitate debugging */
-#define TIMEOUTS_VAL 5
+#define TIMEOUTS_VAL 500000
 
 #define EXPECTED_URI_BASE_PATH  "/"
 
@@ -204,15 +204,6 @@ _mhdErrorExit_func (const char *errDesc, const char 
*funcName, int lineNum)
 
 #define URL_SCHEME_HOST URL_SCHEME URL_HOST
 
-#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"
-
 #define PAGE \
   "<html><head><title>libmicrohttpd demo page</title></head>" \
   "<body>Success!</body></html>"
@@ -225,6 +216,8 @@ _mhdErrorExit_func (const char *errDesc, const char 
*funcName, int lineNum)
 static int verbose;
 static int oneone;                  /**< If false use HTTP/1.0 for requests*/
 
+static struct curl_slist *hdr_broken_cnt_len = NULL;
+
 static void
 test_global_init (void)
 {
@@ -232,63 +225,19 @@ test_global_init (void)
 
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     externalErrorExit ();
+
+  hdr_broken_cnt_len =
+    curl_slist_append (hdr_broken_cnt_len,
+                       MHD_HTTP_HEADER_CONTENT_LENGTH ": 123bad");
 }
 
 
 static void
 test_global_cleanup (void)
 {
-  curl_global_cleanup ();
-}
-
-
-struct headers_check_result
-{
-  unsigned int expected_size;
-  int header1_found;
-  int header2_found;
-  int size_found;
-};
+  curl_slist_free_all (hdr_broken_cnt_len);
 
-static size_t
-lcurl_hdr_callback (char *buffer, size_t size, size_t nitems,
-                    void *userdata)
-{
-  const size_t data_size = size * 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)))
-    check_res->header1_found++;
-  else if ((MHD_STATICSTR_LEN_ (HEADER2_CRLF) == data_size) &&
-           (0 == memcmp (HEADER2_CRLF, buffer, data_size)))
-    check_res->header2_found++;
-  else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ")
-            < data_size) &&
-           (0 ==
-            memcmp (MHD_HTTP_HEADER_CONTENT_LENGTH ": ", buffer,
-                    MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": "))))
-  {
-    char cmpbuf[256];
-    int res;
-    const unsigned int numbers_pos =
-      MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ");
-    res = snprintf (cmpbuf, sizeof(cmpbuf), "%u\r\n", 
check_res->expected_size);
-    if ((res <= 0) || (res > ((int) (sizeof(cmpbuf) - 1))))
-      externalErrorExit ();
-    if (0 != strcmp (buffer + numbers_pos, cmpbuf))
-    {
-      fprintf (stderr, "Wrong Content-Length.\n"
-               "Expected:\n%u\n"
-               "Received:\n%s", check_res->expected_size,
-               buffer + numbers_pos);
-      mhdErrorExitDesc ("Wrong Content-Length");
-    }
-    check_res->size_found++;
-  }
-
-  return data_size;
+  curl_global_cleanup ();
 }
 
 
@@ -308,8 +257,7 @@ copyBuffer (void *ptr,
 {
   (void) ptr; /* Unused, mute compiler warning */
   (void) ctx; /* Unused, mute compiler warning */
-  if ((0 != size) && (0 != nmemb))
-    libcurlErrorExitDesc ("Received unexpected body data");
+  /* Discard data */
   return size * nmemb;
 }
 
@@ -389,15 +337,6 @@ ahcCheck (void *cls,
   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);
@@ -409,34 +348,55 @@ ahcCheck (void *cls,
 }
 
 
-/**
- * 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 int
+libcurl_debug_cb (CURL *handle,
+                  curl_infotype type,
+                  char *data,
+                  size_t size,
+                  void *userptr)
 {
-  if (uri_exist)
+  static const char excess_mark[] = "Excess found";
+  static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
+  (void) handle;
+  (void) userptr;
+
+#ifdef _DEBUG
+  switch (type)
   {
-    if (CURLE_OK !=
-        curl_easy_setopt (c, CURLOPT_URL,
-                          URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
-      libcurlErrorExitDesc ("Cannot set request URL");
+  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:
+#if 0
+    fprintf (stderr, "<| %.*s\n", (int) size, data);
+#endif
+    break;
+  case CURLINFO_DATA_OUT:
+  case CURLINFO_SSL_DATA_IN:
+  case CURLINFO_SSL_DATA_OUT:
+  case CURLINFO_END:
+  default:
+    break;
   }
-  else
+#endif /* _DEBUG */
+  if (CURLINFO_TEXT == type)
   {
-    if (CURLE_OK !=
-        curl_easy_setopt (c, CURLOPT_URL,
-                          URL_SCHEME_HOST EXPECTED_URI_BASE_PATH_MISSING))
-      libcurlErrorExitDesc ("Cannot set request URL");
+    if ((size >= excess_mark_len) &&
+        (0 == memcmp (data, excess_mark, excess_mark_len)))
+      mhdErrorExitDesc ("Extra data has been detected in MHD reply");
   }
+  return 0;
 }
 
 
 static CURL *
-setupCURL (void *cbc, uint16_t port,
-           struct headers_check_result *hdr_chk_result)
+setupCURL (void *cbc, uint16_t port)
 {
   CURL *c;
 
@@ -456,16 +416,14 @@ setupCURL (void *cbc, uint16_t port,
                                      CURL_HTTP_VERSION_1_0)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
                                      ((long) TIMEOUTS_VAL))) ||
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERFUNCTION,
-                                     lcurl_hdr_callback)) ||
-      (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERDATA,
-                                     hdr_chk_result)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
                                      libcurl_errbuf)) ||
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
 #ifdef _DEBUG
       (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
 #endif /* _DEBUG */
+      (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
+                                     &libcurl_debug_cb)) ||
 #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) */
@@ -475,10 +433,21 @@ setupCURL (void *cbc, uint16_t port,
       (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))
+  if (CURLE_OK !=
+      curl_easy_setopt (c, CURLOPT_URL,
+                        URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
+    libcurlErrorExitDesc ("Cannot set request URI");
+
+  /* Set as a "custom" request, because no actual upload data is provided. */
+  if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST,
+                                    MHD_HTTP_METHOD_PUT))
     libcurlErrorExitDesc ("curl_easy_setopt() failed");
 
+  if (CURLE_OK !=
+      curl_easy_setopt (c, CURLOPT_HTTPHEADER,
+                        hdr_broken_cnt_len))
+    libcurlErrorExitDesc ("Cannot set '" MHD_HTTP_HEADER_CONTENT_LENGTH 
"'.\n");
+
   return c;
 }
 
@@ -562,6 +531,15 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
       mhdErrorExitDesc ("MHD_get_fdset() failed");
     tv.tv_sec = 0;
     tv.tv_usec = 200000;
+    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;
+    }
 #ifdef MHD_POSIX_SOCKETS
     if (maxMhdSk > maxCurlSk)
       maxCurlSk = maxMhdSk;
@@ -575,7 +553,7 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
       if ((WSAEINVAL != WSAGetLastError ()) ||
           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
         externalErrorExitDesc ("Unexpected select() error");
-      Sleep (200);
+      Sleep ((unsigned long) tv.tv_usec / 1000);
 #endif
     }
     if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
@@ -593,11 +571,9 @@ performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM 
**multi_reuse)
  * @return non-zero if success, zero if failed
  */
 static unsigned int
-check_result (CURLcode curl_code, CURL *c, long expected_code,
-              struct headers_check_result *hdr_res)
+check_result (CURLcode curl_code, CURL *c, long expected_code)
 {
   long code;
-  unsigned int ret;
 
   if (CURLE_OK != curl_code)
   {
@@ -628,54 +604,17 @@ check_result (CURLcode curl_code, CURL *c, long 
expected_code,
   else if (verbose)
     printf ("The response has expected HTTP code: %ld\n", expected_code);
 
-  ret = 1;
-  if (1 != hdr_res->header1_found)
-  {
-    if (0 == hdr_res->header1_found)
-      fprintf (stderr, "Response header1 was not found.\n");
-    else
-      fprintf (stderr, "Response header1 was found %d times "
-               "instead of one time only.\n", hdr_res->header1_found);
-    ret = 0;
-  }
-  else if (verbose)
-    printf ("Header1 is present in the response.\n");
-  if (1 != hdr_res->header2_found)
-  {
-    if (0 == hdr_res->header2_found)
-      fprintf (stderr, "Response header2 was not found.\n");
-    else
-      fprintf (stderr, "Response header2 was found %d times "
-               "instead of one time only.\n", hdr_res->header2_found);
-    ret = 0;
-  }
-  else if (verbose)
-    printf ("Header2 is present in the response.\n");
-  if (1 != hdr_res->size_found)
-  {
-    if (0 == hdr_res->size_found)
-      fprintf (stderr, "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);
-    ret = 0;
-  }
-  else if (verbose)
-    printf ("'Content-Length' header with correct value "
-            "is present in the response.\n");
-
-  return ret;
+  return ! 0;
 }
 
 
 static unsigned int
-testHead (void)
+performTest (void)
 {
   struct MHD_Daemon *d;
   uint16_t port;
   struct CBC cbc;
   struct ahc_cls_type ahc_param;
-  struct headers_check_result rp_headers_check;
   char buf[2048];
   CURL *c;
   CURLM *multi_reuse;
@@ -705,22 +644,17 @@ testHead (void)
   }
 
   /* First request */
-  ahc_param.rq_method = MHD_HTTP_METHOD_HEAD;
+  ahc_param.rq_method = MHD_HTTP_METHOD_PUT;
   ahc_param.rq_url = EXPECTED_URI_BASE_PATH;
-  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);
-  c = setupCURL (&cbc, port, &rp_headers_check);
-  setCURL_rq_path (c, 1);
+  c = setupCURL (&cbc, port);
   multi_reuse = NULL;
   /* First request */
   if (check_result (performQueryExternal (d, c, &multi_reuse), c,
-                    MHD_HTTP_OK, &rp_headers_check))
+                    MHD_HTTP_BAD_REQUEST))
   {
     fflush (stderr);
     if (verbose)
@@ -734,15 +668,9 @@ testHead (void)
     failed = 1;
   }
   /* Second request */
-  rp_headers_check.expected_size = MHD_STATICSTR_LEN_ (PAGE_404);
-  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);
   if (check_result (performQueryExternal (d, c, &multi_reuse), c,
-                    MHD_HTTP_NOT_FOUND, &rp_headers_check))
+                    MHD_HTTP_BAD_REQUEST))
   {
     fflush (stderr);
     if (verbose)
@@ -756,15 +684,12 @@ testHead (void)
     failed = 1;
   }
   /* Third request */
-  rp_headers_check.header1_found = 0;
-  rp_headers_check.header2_found = 0;
-  rp_headers_check.size_found = 0;
   cbc.pos = 0; /* Reset buffer position */
   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_BAD_REQUEST))
   {
     fflush (stderr);
     if (verbose)
@@ -801,7 +726,7 @@ main (int argc, char *const *argv)
 
   test_global_init ();
 
-  errorCount += testHead ();
+  errorCount += performTest ();
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
   test_global_cleanup ();

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