gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (237aebfa -> 182ed3a0)


From: gnunet
Subject: [libmicrohttpd] branch master updated (237aebfa -> 182ed3a0)
Date: Wed, 28 Jul 2021 10:36:59 +0200

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 237aebfa mhd_str: use smaller include
     new ee3f3222 Added internal functions for printing decimal and hex numbers
     new 2cab7e09 try_ready_chunked_body: use new string function, fixes.
     new 678dcd09 response: use auto flag for chunked encoding header
     new 28223f6a keepalive_possible(): check whether app requested close
     new bbf0a296 Re-written chunk footer generation function as a separate 
function
     new 140f4844 Added new public API function MHD_get_reason_phrase_len_for()
     new 182ed3a0 response: use macro instead of string for connection header

The 7 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:
 contrib/gen_http_statuses_inserts.sh |  11 +-
 src/include/microhttpd.h             |  11 +-
 src/microhttpd/.gitignore            |   1 +
 src/microhttpd/Makefile.am           |   4 +
 src/microhttpd/connection.c          | 267 ++++++++++++++++++++++++++----
 src/microhttpd/mhd_str.c             |  68 ++++++++
 src/microhttpd/mhd_str.h             |  42 +++++
 src/microhttpd/reason_phrase.c       | 240 ++++++++++++++-------------
 src/microhttpd/response.c            |  42 ++++-
 src/microhttpd/test_http_reasons.c   |  34 +++-
 src/microhttpd/test_str.c            | 310 +++++++++++++++++++++++++++++++++++
 11 files changed, 860 insertions(+), 170 deletions(-)

diff --git a/contrib/gen_http_statuses_inserts.sh 
b/contrib/gen_http_statuses_inserts.sh
index 6c8e6454..3a7dedb1 100755
--- a/contrib/gen_http_statuses_inserts.sh
+++ b/contrib/gen_http_statuses_inserts.sh
@@ -70,10 +70,10 @@ FNR > 1 {
   desc = $3
   if (num % 100 == 0) {
     if (num != 100) {
-      printf ("  /* %s */ %-24s /* %s */\n};\n\n", prev_num, 
"\""prev_reason"\"", prev_desc)
+      printf ("  /* %s */ %-36s /* %s */\n};\n\n", prev_num, "_MHD_S_STR_W_LEN 
(\""prev_reason"\")", prev_desc)
     }
     prev_num = num;
-    print "static const char *const " hundreds[$1/100] "_hundred[] = {"
+    print "static const struct _MHD_str_w_len " hundreds[$1/100] "_hundred[] = 
{"
   }
   if (num == 306) { 
     reason = "Switch Proxy" 
@@ -81,20 +81,21 @@ FNR > 1 {
   }
   if (reason == "Unassigned") next
   if (prev_num != num)
-    printf ("  /* %s */ %-24s /* %s */\n", prev_num, "\""prev_reason"\",", 
prev_desc)
+    printf ("  /* %s */ %-36s /* %s */\n", prev_num, "_MHD_S_STR_W_LEN 
(\""prev_reason"\"),", prev_desc)
   while(++prev_num < num) {
     if (prev_num == 449) {prev_reason="Reply With"; prev_desc="MS IIS 
extension";}
     else if (prev_num == 450) {prev_reason="Blocked by Windows Parental 
Controls"; prev_desc="MS extension";}
     else if (prev_num == 509) {prev_reason="Bandwidth Limit Exceeded"; 
prev_desc="Apache extension";}
     else {prev_reason="Unknown"; prev_desc="Not used";}
-    printf ("  /* %s */ %-24s /* %s */\n", prev_num, "\""prev_reason"\",", 
prev_desc)
+    if (prev_reason=="Unknown") printf ("  /* %s */ %-36s /* %s */\n", 
prev_num, "{\""prev_reason"\", 0},", prev_desc)
+    else printf ("  /* %s */ %-36s /* %s */\n", prev_num, "_MHD_S_STR_W_LEN 
(\""prev_reason"\"),", prev_desc)
   }
   prev_num = num
   prev_reason = reason
   prev_desc = desc
 }
 END {
-  printf ("  /* %s */ %-24s /* %s */\n};\n", prev_num, "\""prev_reason"\"", 
prev_desc)
+  printf ("  /* %s */ %-36s /* %s */\n};\n", prev_num, "_MHD_S_STR_W_LEN 
(\""prev_reason"\")", prev_desc)
 }' http-status-codes-1.csv > code_insert_statuses.c && \
 echo OK && \
 rm http-status-codes-1.csv || exit
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 6e266751..fe52ad7f 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -343,7 +343,7 @@ _MHD_DEPR_MACRO (
  * @defgroup httpcode HTTP response codes.
  * These are the status codes defined for HTTP responses.
  * See: 
https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
- * Registry export date: 2019-06-09
+ * Registry export date: 2021-06-08
  * @{
  */
 
@@ -544,6 +544,15 @@ _MHD_EXTERN const char *
 MHD_get_reason_phrase_for (unsigned int code);
 
 
+/**
+ * Returns the length of the string reason phrase for a response code.
+ *
+ * If message string is not available for a status code,
+ * 0 is returned.
+ */
+_MHD_EXTERN size_t
+MHD_get_reason_phrase_len_for (unsigned int code);
+
 /**
  * Flag to be or-ed with MHD_HTTP status code for
  * SHOUTcast.  This will cause the response to begin
diff --git a/src/microhttpd/.gitignore b/src/microhttpd/.gitignore
index 3b0d8ce4..11f4f587 100644
--- a/src/microhttpd/.gitignore
+++ b/src/microhttpd/.gitignore
@@ -48,6 +48,7 @@ test_http_reasons
 /test_shutdown_select_ignore
 /test_str_compare
 /test_str_to_value
+/test_str_from_value
 /test_upgrade
 /test_upgrade_ssl
 /test_options
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index e610c1df..fb10b0a2 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -157,6 +157,7 @@ endif
 check_PROGRAMS = \
   test_str_compare \
   test_str_to_value \
+  test_str_from_value \
   test_str_token \
   test_str_token_remove \
   test_str_tokens_remove \
@@ -358,6 +359,9 @@ test_str_compare_SOURCES = \
 test_str_to_value_SOURCES = \
   test_str.c test_helpers.h mhd_str.c mhd_str.h
 
+test_str_from_value_SOURCES = \
+  test_str.c test_helpers.h mhd_str.c mhd_str.h
+
 test_str_token_SOURCES = \
   test_str_token.c mhd_str.c mhd_str.h
 
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 9a8209ed..4ef6c5c3 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -994,18 +994,26 @@ try_ready_chunked_body (struct MHD_Connection *connection)
   ssize_t ret;
   struct MHD_Response *response;
   static const size_t max_chunk = 0xFFFFFF;
-  char cbuf[10];                /* 10: max strlen of "FFFFFF\r\n" */
-  int cblen;
+  char chunk_hdr[6];            /* 6: max strlen of "FFFFFF" */
+  /* "FFFFFF" + "\r\n" */
+  static const size_t max_chunk_hdr_len = sizeof(chunk_hdr) + 2;
+  /* "FFFFFF" + "\r\n" + "\r\n" (chunk termination) */
+  static const size_t max_chunk_overhead = sizeof(chunk_hdr) + 2 + 2;
+  size_t chunk_hdr_len;
 
   response = connection->response;
   if (NULL == response->crc)
     return MHD_YES;
-  if (0 == connection->write_buffer_size)
+
+  mhd_assert (0 == connection->write_buffer_append_offset);
+
+  /* The buffer must reasonably large enough */
+  if (128 > connection->write_buffer_size)
   {
     size_t size;
 
-    size = MHD_pool_get_free (connection->pool);
-    if (size < 128)
+    size = connection->write_buffer_size + MHD_pool_get_free 
(connection->pool);
+    if (128 > size)
     {
 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
       MHD_mutex_unlock_chk_ (&response->mutex);
@@ -1015,11 +1023,13 @@ try_ready_chunked_body (struct MHD_Connection 
*connection)
                               _ ("Closing connection (out of memory)."));
       return MHD_NO;
     }
-    if ( (max_chunk + sizeof(cbuf) + 2) < size)
-      size = max_chunk + sizeof(cbuf) + 2;
-    connection->write_buffer = MHD_pool_allocate (connection->pool,
-                                                  size,
-                                                  false);
+    /* Limit the buffer size to the large 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);
     connection->write_buffer_size = size;
   }
@@ -1037,9 +1047,9 @@ try_ready_chunked_body (struct MHD_Connection *connection)
       = (size_t) (connection->response_write_position - response->data_start);
     /* buffer already ready, use what is there for the chunk */
     ret = response->data_size - data_write_offset;
-    if ( ((size_t) ret) > connection->write_buffer_size - sizeof (cbuf) - 2)
-      ret = connection->write_buffer_size - sizeof (cbuf) - 2;
-    memcpy (&connection->write_buffer[sizeof (cbuf)],
+    if ( ((size_t) ret) > connection->write_buffer_size - max_chunk_overhead)
+      ret = connection->write_buffer_size - max_chunk_overhead;
+    memcpy (&connection->write_buffer[max_chunk_hdr_len],
             &response->data[data_write_offset],
             ret);
   }
@@ -1048,12 +1058,13 @@ try_ready_chunked_body (struct MHD_Connection 
*connection)
     /* buffer not in range, try to fill it */
     size_t size_to_fill;
 
-    size_to_fill = connection->write_buffer_size - sizeof (cbuf) - 2;
+    size_to_fill = connection->write_buffer_size - max_chunk_overhead;
+    /* Limit size for the callback to the max usable size */
     if (max_chunk < size_to_fill)
       size_to_fill = max_chunk;
     ret = response->crc (response->crc_cls,
                          connection->response_write_position,
-                         &connection->write_buffer[sizeof (cbuf)],
+                         &connection->write_buffer[max_chunk_hdr_len],
                          size_to_fill);
   }
   if ( ((ssize_t) MHD_CONTENT_READER_END_WITH_ERROR) == ret)
@@ -1072,11 +1083,12 @@ try_ready_chunked_body (struct MHD_Connection 
*connection)
        (0 == response->total_size) )
   {
     /* end of message, signal other side! */
-    memcpy (connection->write_buffer,
-            "0\r\n",
-            3);
+    connection->write_buffer[0] = '0';
+    connection->write_buffer[1] = '\r';
+    connection->write_buffer[2] = '\n';
     connection->write_buffer_append_offset = 3;
     connection->write_buffer_send_offset = 0;
+    /* TODO: remove update of the response size */
     response->total_size = connection->response_write_position;
     return MHD_YES;
   }
@@ -1088,21 +1100,20 @@ try_ready_chunked_body (struct MHD_Connection 
*connection)
 #endif
     return MHD_NO;
   }
-  cblen = MHD_snprintf_ (cbuf,
-                         sizeof (cbuf),
-                         "%X\r\n",
-                         (unsigned int) ret);
-  mhd_assert (cblen > 0);
-  mhd_assert ((size_t) cblen < sizeof(cbuf));
-  memcpy (&connection->write_buffer[sizeof (cbuf) - cblen],
-          cbuf,
-          cblen);
-  memcpy (&connection->write_buffer[sizeof (cbuf) + ret],
-          "\r\n",
-          2);
+  chunk_hdr_len = MHD_uint32_to_strx (ret, chunk_hdr, sizeof(chunk_hdr));
+  mhd_assert (chunk_hdr_len != 0);
+  mhd_assert (chunk_hdr_len < sizeof(chunk_hdr));
+  connection->write_buffer_send_offset =
+    (max_chunk_hdr_len - (chunk_hdr_len + 2));
+  memcpy (connection->write_buffer + connection->write_buffer_send_offset,
+          chunk_hdr,
+          chunk_hdr_len);
+  connection->write_buffer[max_chunk_hdr_len - 2] = '\r';
+  connection->write_buffer[max_chunk_hdr_len - 1] = '\n';
+  connection->write_buffer[max_chunk_hdr_len + ret] = '\r';
+  connection->write_buffer[max_chunk_hdr_len + ret + 1] = '\n';
   connection->response_write_position += ret;
-  connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
-  connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
+  connection->write_buffer_append_offset = max_chunk_hdr_len + ret + 2;
   return MHD_YES;
 }
 
@@ -1134,6 +1145,10 @@ keepalive_possible (struct MHD_Connection *connection)
   if ( (NULL != connection->response) &&
        (0 != (connection->response->flags & MHD_RF_HTTP_VERSION_1_0_ONLY) ) )
     return MHD_NO;
+  if ( (NULL != connection->response) &&
+       (0 != (connection->response->flags_auto
+              & MHD_RAF_HAS_CONNECTION_CLOSE) ) )
+    return MHD_NO;
 
   if (MHD_IS_HTTP_VER_1_1_COMPAT (connection->http_ver) &&
       ( (NULL == connection->response) ||
@@ -1292,6 +1307,121 @@ try_grow_read_buffer (struct MHD_Connection *connection,
 }
 
 
+/**
+ * Shrink connection read buffer to the zero of data in the buffer
+ * @param connection the connection whose read buffer is being manipulated
+ */
+static void
+connection_shrink_read_buffer (struct MHD_Connection *connection)
+{
+  struct MHD_Connection *const c = connection; /**< a short alias */
+  void *new_buf;
+
+  if (NULL == c->read_buffer)
+  {
+    mhd_assert (0 == c->read_buffer_size);
+    mhd_assert (0 == c->read_buffer_offset);
+    c->read_buffer = NULL;
+    return;
+  }
+
+  mhd_assert (c->read_buffer_offset <= c->read_buffer_size);
+  new_buf = MHD_pool_reallocate (c->pool, c->read_buffer, c->read_buffer_size,
+                                 c->read_buffer_offset);
+  mhd_assert (c->read_buffer == new_buf);
+  c->read_buffer_size = c->read_buffer_offset;
+  if (0 == c->read_buffer_size)
+    c->read_buffer = NULL;
+}
+
+
+/**
+ * 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.
+ */
+static size_t
+connection_maximize_write_buffer (struct MHD_Connection *connection)
+{
+  struct MHD_Connection *const c = connection; /**< a short alias */
+  struct MemoryPool *const pool = connection->pool;
+  void *new_buf;
+  size_t new_size;
+
+  mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
+  mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset);
+  mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset);
+
+  new_size = c->write_buffer_size + MHD_pool_get_free (pool);
+  new_buf = MHD_pool_reallocate (pool,
+                                 c->write_buffer,
+                                 c->write_buffer_size,
+                                 new_size);
+  /* Buffer position must not be moved.
+   * Position could be moved only if buffer was allocated 'from_end',
+   * which cannot happen. */
+  mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer));
+  c->write_buffer = new_buf;
+  c->write_buffer_size = new_size;
+  if (c->write_buffer_send_offset == c->write_buffer_append_offset)
+  {
+    /* All data have been sent, reset offsets to zero. */
+    c->write_buffer_send_offset = 0;
+    c->write_buffer_append_offset = 0;
+  }
+
+  return c->write_buffer_size - c->write_buffer_append_offset;
+}
+
+
+/**
+ * Shrink connection write buffer to the size of unsent data.
+ *
+ * @note: The number of calls of this function should be limited to avoid extra
+ * zeroing of the memory.
+ * @param connection the connection whose write buffer is being manipulated
+ * @param connection the connection to manipulate write buffer
+ */
+static void
+connection_shrink_write_buffer (struct MHD_Connection *connection)
+{
+  struct MHD_Connection *const c = connection; /**< a short alias */
+  struct MemoryPool *const pool = connection->pool;
+  void *new_buf;
+
+  mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
+  mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset);
+  mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset);
+
+  if (NULL == c->write_buffer)
+    return;
+  if (c->write_buffer_append_offset == c->write_buffer_size)
+    return;
+
+  new_buf = MHD_pool_reallocate (pool, c->write_buffer, c->write_buffer_size,
+                                 c->write_buffer_append_offset);
+  mhd_assert (c->write_buffer == new_buf);
+  c->write_buffer_size = c->write_buffer_append_offset;
+}
+
+
+/**
+ * Switch connection from recv mode to send mode.
+ *
+ * Current request header or body will not be read anymore,
+ * response must be assigned to connection.
+ * @param connection the connection to prepare for sending.
+ */
+static void
+connection_switch_from_recv_to_send (struct MHD_Connection *connection)
+{
+  /* Read buffer is not needed for this request, shrink it.*/
+  connection_shrink_read_buffer (connection);
+}
+
+
 /**
  * Allocate the connection's write buffer and fill it with all of the
  * headers (or footers, if we have already sent the body) from the
@@ -1666,6 +1796,72 @@ build_header_response (struct MHD_Connection *connection)
 }
 
 
+/**
+ * Allocate the connection's write buffer (if necessary) and fill it
+ * with response footers.
+ * Works only for chunked responses as other responses do not need
+ * and do not support any kind of footers.
+ *
+ * @param connection the connection
+ * @return #MHD_YES on success, #MHD_NO on failure (out of memory)
+ */
+static enum MHD_Result
+build_connection_chunked_response_footer (struct MHD_Connection *connection)
+{
+  char *buf;           /**< the buffer to write footers to */
+  size_t buf_size;     /**< the size of the @a buf */
+  size_t used_size;    /**< the used size of the @a buf */
+  struct MHD_Connection *const c = connection; /**< a short alias */
+  struct MHD_HTTP_Header *pos;
+
+  /* TODO: replace with 'use_chunked_send' */
+  mhd_assert (connection->have_chunked_upload);
+  /* TODO: allow combining of the final footer with the last chunk,
+   * modify the next assert. */
+  mhd_assert (MHD_CONNECTION_BODY_SENT == connection->state);
+  mhd_assert (NULL != c->response);
+
+  buf_size = connection_maximize_write_buffer (c);
+  /* '2' is the minimal size of chunked footer ("\r\n") */
+  if (buf_size < 2)
+    return MHD_NO;
+  buf = c->write_buffer + c->write_buffer_append_offset;
+  used_size = 0;
+
+  for (pos = c->response->first_header; NULL != pos; pos = pos->next)
+  {
+    if (MHD_FOOTER_KIND == pos->kind)
+    {
+      size_t new_used_size; /* resulting size with this header */
+      /* '4' is colon, space, linefeeds */
+      new_used_size = used_size + pos->header_size + pos->value_size + 4;
+      if (new_used_size > buf_size)
+        return MHD_NO;
+      memcpy (buf + used_size, pos->header, pos->header_size);
+      used_size += pos->header_size;
+      buf[used_size++] = ':';
+      buf[used_size++] = ' ';
+      memcpy (buf + used_size, pos->value, pos->value_size);
+      used_size += pos->value_size;
+      buf[used_size++] = '\r';
+      buf[used_size++] = '\n';
+      mhd_assert (used_size == new_used_size);
+    }
+  }
+  if (used_size + 2 > buf_size)
+    return MHD_NO;
+  memcpy (buf + used_size, "\r\n", 2);
+  used_size += 2;
+
+  c->write_buffer_append_offset += used_size;
+  mhd_assert (c->write_buffer_append_offset <= c->write_buffer_size);
+
+  /* TODO: remove shrink */
+  connection_shrink_write_buffer (c);
+  return MHD_YES;
+}
+
+
 /**
  * We encountered an error processing the request.
  * Handle it properly by stopping to read data
@@ -3790,6 +3986,8 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
         continue;
       if (NULL == connection->response)
         break;                  /* try again next time */
+
+      connection_switch_from_recv_to_send (connection);
       if (MHD_NO == build_header_response (connection))
       {
         /* oops - close! */
@@ -3903,7 +4101,10 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
       /* mutex was already unlocked by try_ready_chunked_body */
       break;
     case MHD_CONNECTION_BODY_SENT:
-      if (MHD_NO == build_header_response (connection))
+      /* TODO: replace with 'use_chunked_send' */
+      mhd_assert (connection->have_chunked_upload);
+
+      if (MHD_NO == build_connection_chunked_response_footer (connection))
       {
         /* oops - close! */
         CONNECTION_CLOSE_ERROR (connection,
diff --git a/src/microhttpd/mhd_str.c b/src/microhttpd/mhd_str.c
index 60c198bc..1d4b9257 100644
--- a/src/microhttpd/mhd_str.c
+++ b/src/microhttpd/mhd_str.c
@@ -32,6 +32,7 @@
 
 #include "mhd_assert.h"
 #include "mhd_limits.h"
+#include "mhd_assert.h"
 
 #ifdef MHD_FAVOR_SMALL_CODE
 #ifdef _MHD_static_inline
@@ -1184,3 +1185,70 @@ MHD_str_to_uvalue_n_ (const char *str,
 
 
 #endif /* MHD_FAVOR_SMALL_CODE */
+
+
+size_t
+MHD_uint32_to_strx (uint32_t val,
+                    char *buf,
+                    size_t buf_size)
+{
+  char *chr; /**< pointer to the current printed digit */
+  int digit_pos = 7; /** zero-based, digit position in @a 'val' */
+  int digit;
+
+  chr = buf;
+  digit = (int) (((val) >> (4 * digit_pos)) & 0xf);
+
+  /* Skip leading zeros */
+  while ((0 == digit) && (0 != digit_pos))
+    digit = (int) (((val) >> (4 * --digit_pos)) & 0xf);
+
+  while (0 != buf_size)
+  {
+    *chr = (digit <= 9) ? ('0' + (char) digit) : ('A' + (char) digit - 10);
+    chr++;
+    buf_size--;
+    if (0 == digit_pos)
+      return (size_t) (chr - buf);
+    digit = (int) (((val) >> (4 * --digit_pos)) & 0xf);
+  }
+  return 0; /* The buffer is too small */
+}
+
+
+size_t
+MHD_uint16_to_str (uint16_t val,
+                   char *buf,
+                   size_t buf_size)
+{
+  char *chr;  /**< pointer to the current printed digit */
+  /* The biggest printable number is 65535 */
+  uint16_t divisor = UINT16_C (10000);
+  int digit;
+
+  chr = buf;
+  digit = (int) (val / divisor);
+  mhd_assert (digit < 10);
+
+  /* Do not print leading zeros */
+  while ((0 == digit) && (1 < divisor))
+  {
+    divisor /= 10;
+    digit = (int) (val / divisor);
+    mhd_assert (digit < 10);
+  }
+
+  while (0 != buf_size)
+  {
+    *chr = (char) digit + '0';
+    chr++;
+    buf_size--;
+    if (1 == divisor)
+      return (size_t) (chr - buf);
+    val %= divisor;
+    divisor /= 10;
+    digit = (int) (val / divisor);
+    mhd_assert (digit < 10);
+  }
+  return 0; /* The buffer is too small */
+}
diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h
index 0bd46444..91d5f46e 100644
--- a/src/microhttpd/mhd_str.h
+++ b/src/microhttpd/mhd_str.h
@@ -50,6 +50,18 @@ typedef intptr_t ssize_t;
 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
 #endif /* ! MHD_STATICSTR_LEN_ */
 
+struct _MHD_str_w_len
+{
+  const char *str;
+  const size_t len;
+};
+
+/**
+ * Static string initialiser for struct _MHD_str_w_len
+ */
+#define _MHD_S_STR_W_LEN(str) { str, MHD_STATICSTR_LEN_(str) }
+
+
 /*
  * Block of functions/macros that use US-ASCII charset as required by HTTP
  * standards. Not affected by current locale settings.
@@ -361,4 +373,34 @@ MHD_str_to_uvalue_n_ (const char *str,
 
 #endif /* MHD_FAVOR_SMALL_CODE */
 
+
+/**
+ * Convert uint32_t value to hexdecimal US-ASCII string.
+ * @note: result is NOT zero-terminated.
+ * @param val the value to convert
+ * @param buf the buffer to result to
+ * @param buf_size size of the @a buffer
+ * @return number of charters has been put to the @a buf,
+ *         zero if buffer is too small (buffer may be modified).
+ */
+size_t
+MHD_uint32_to_strx (uint32_t val,
+                    char *buf,
+                    size_t buf_size);
+
+
+/**
+ * Convert uint16_t value to decimal US-ASCII string.
+ * @note: result is NOT zero-terminated.
+ * @param val the value to convert
+ * @param buf the buffer to result to
+ * @param buf_size size of the @a buffer
+ * @return number of charters has been put to the @a buf,
+ *         zero if buffer is too small (buffer may be modified).
+ */
+size_t
+MHD_uint16_to_str (uint16_t val,
+                   char *buf,
+                   size_t buf_size);
+
 #endif /* MHD_STR_H */
diff --git a/src/microhttpd/reason_phrase.c b/src/microhttpd/reason_phrase.c
index 4e54d920..969cf95a 100644
--- a/src/microhttpd/reason_phrase.c
+++ b/src/microhttpd/reason_phrase.c
@@ -26,142 +26,143 @@
  */
 #include "platform.h"
 #include "microhttpd.h"
+#include "mhd_str.h"
 
 #ifndef NULL
 #define NULL ((void*) 0)
 #endif
 
-static const char *const invalid_hundred[] = {
-  NULL
+static const struct _MHD_str_w_len invalid_hundred[] = {
+  { NULL, 0 }
 };
 
-static const char *const one_hundred[] = {
-  /* 100 */ "Continue",              /* RFC7231, Section 6.2.1 */
-  /* 101 */ "Switching Protocols",   /* RFC7231, Section 6.2.2 */
-  /* 102 */ "Processing",            /* RFC2518 */
-  /* 103 */ "Early Hints"            /* RFC8297 */
+static const struct _MHD_str_w_len one_hundred[] = {
+  /* 100 */ _MHD_S_STR_W_LEN ("Continue"),       /* RFC7231, Section 6.2.1 */
+  /* 101 */ _MHD_S_STR_W_LEN ("Switching Protocols"), /* RFC7231, Section 
6.2.2 */
+  /* 102 */ _MHD_S_STR_W_LEN ("Processing"),     /* RFC2518 */
+  /* 103 */ _MHD_S_STR_W_LEN ("Early Hints")     /* RFC8297 */
 };
 
-static const char *const two_hundred[] = {
-  /* 200 */ "OK",                    /* RFC7231, Section 6.3.1 */
-  /* 201 */ "Created",               /* RFC7231, Section 6.3.2 */
-  /* 202 */ "Accepted",              /* RFC7231, Section 6.3.3 */
-  /* 203 */ "Non-Authoritative Information", /* RFC7231, Section 6.3.4 */
-  /* 204 */ "No Content",            /* RFC7231, Section 6.3.5 */
-  /* 205 */ "Reset Content",         /* RFC7231, Section 6.3.6 */
-  /* 206 */ "Partial Content",       /* RFC7233, Section 4.1 */
-  /* 207 */ "Multi-Status",          /* RFC4918 */
-  /* 208 */ "Already Reported",      /* RFC5842 */
-  /* 209 */ "Unknown",               /* Not used */
-  /* 210 */ "Unknown",               /* Not used */
-  /* 211 */ "Unknown",               /* Not used */
-  /* 212 */ "Unknown",               /* Not used */
-  /* 213 */ "Unknown",               /* Not used */
-  /* 214 */ "Unknown",               /* Not used */
-  /* 215 */ "Unknown",               /* Not used */
-  /* 216 */ "Unknown",               /* Not used */
-  /* 217 */ "Unknown",               /* Not used */
-  /* 218 */ "Unknown",               /* Not used */
-  /* 219 */ "Unknown",               /* Not used */
-  /* 220 */ "Unknown",               /* Not used */
-  /* 221 */ "Unknown",               /* Not used */
-  /* 222 */ "Unknown",               /* Not used */
-  /* 223 */ "Unknown",               /* Not used */
-  /* 224 */ "Unknown",               /* Not used */
-  /* 225 */ "Unknown",               /* Not used */
-  /* 226 */ "IM Used"                /* RFC3229 */
+static const struct _MHD_str_w_len two_hundred[] = {
+  /* 200 */ _MHD_S_STR_W_LEN ("OK"),             /* RFC7231, Section 6.3.1 */
+  /* 201 */ _MHD_S_STR_W_LEN ("Created"),        /* RFC7231, Section 6.3.2 */
+  /* 202 */ _MHD_S_STR_W_LEN ("Accepted"),       /* RFC7231, Section 6.3.3 */
+  /* 203 */ _MHD_S_STR_W_LEN ("Non-Authoritative Information"), /* RFC7231, 
Section 6.3.4 */
+  /* 204 */ _MHD_S_STR_W_LEN ("No Content"),     /* RFC7231, Section 6.3.5 */
+  /* 205 */ _MHD_S_STR_W_LEN ("Reset Content"),  /* RFC7231, Section 6.3.6 */
+  /* 206 */ _MHD_S_STR_W_LEN ("Partial Content"), /* RFC7233, Section 4.1 */
+  /* 207 */ _MHD_S_STR_W_LEN ("Multi-Status"),   /* RFC4918 */
+  /* 208 */ _MHD_S_STR_W_LEN ("Already Reported"), /* RFC5842 */
+  /* 209 */ {"Unknown", 0},                      /* Not used */
+  /* 210 */ {"Unknown", 0},                      /* Not used */
+  /* 211 */ {"Unknown", 0},                      /* Not used */
+  /* 212 */ {"Unknown", 0},                      /* Not used */
+  /* 213 */ {"Unknown", 0},                      /* Not used */
+  /* 214 */ {"Unknown", 0},                      /* Not used */
+  /* 215 */ {"Unknown", 0},                      /* Not used */
+  /* 216 */ {"Unknown", 0},                      /* Not used */
+  /* 217 */ {"Unknown", 0},                      /* Not used */
+  /* 218 */ {"Unknown", 0},                      /* Not used */
+  /* 219 */ {"Unknown", 0},                      /* Not used */
+  /* 220 */ {"Unknown", 0},                      /* Not used */
+  /* 221 */ {"Unknown", 0},                      /* Not used */
+  /* 222 */ {"Unknown", 0},                      /* Not used */
+  /* 223 */ {"Unknown", 0},                      /* Not used */
+  /* 224 */ {"Unknown", 0},                      /* Not used */
+  /* 225 */ {"Unknown", 0},                      /* Not used */
+  /* 226 */ _MHD_S_STR_W_LEN ("IM Used")         /* RFC3229 */
 };
 
-static const char *const three_hundred[] = {
-  /* 300 */ "Multiple Choices",      /* RFC7231, Section 6.4.1 */
-  /* 301 */ "Moved Permanently",     /* RFC7231, Section 6.4.2 */
-  /* 302 */ "Found",                 /* RFC7231, Section 6.4.3 */
-  /* 303 */ "See Other",             /* RFC7231, Section 6.4.4 */
-  /* 304 */ "Not Modified",          /* RFC7232, Section 4.1 */
-  /* 305 */ "Use Proxy",             /* RFC7231, Section 6.4.5 */
-  /* 306 */ "Switch Proxy",          /* Not used! RFC7231, Section 6.4.6 */
-  /* 307 */ "Temporary Redirect",    /* RFC7231, Section 6.4.7 */
-  /* 308 */ "Permanent Redirect"     /* RFC7538 */
+static const struct _MHD_str_w_len three_hundred[] = {
+  /* 300 */ _MHD_S_STR_W_LEN ("Multiple Choices"), /* RFC7231, Section 6.4.1 */
+  /* 301 */ _MHD_S_STR_W_LEN ("Moved Permanently"), /* RFC7231, Section 6.4.2 
*/
+  /* 302 */ _MHD_S_STR_W_LEN ("Found"),          /* RFC7231, Section 6.4.3 */
+  /* 303 */ _MHD_S_STR_W_LEN ("See Other"),      /* RFC7231, Section 6.4.4 */
+  /* 304 */ _MHD_S_STR_W_LEN ("Not Modified"),   /* RFC7232, Section 4.1 */
+  /* 305 */ _MHD_S_STR_W_LEN ("Use Proxy"),      /* RFC7231, Section 6.4.5 */
+  /* 306 */ _MHD_S_STR_W_LEN ("Switch Proxy"),   /* Not used! RFC7231, Section 
6.4.6 */
+  /* 307 */ _MHD_S_STR_W_LEN ("Temporary Redirect"), /* RFC7231, Section 6.4.7 
*/
+  /* 308 */ _MHD_S_STR_W_LEN ("Permanent Redirect") /* RFC7538 */
 };
 
-static const char *const four_hundred[] = {
-  /* 400 */ "Bad Request",           /* RFC7231, Section 6.5.1 */
-  /* 401 */ "Unauthorized",          /* RFC7235, Section 3.1 */
-  /* 402 */ "Payment Required",      /* RFC7231, Section 6.5.2 */
-  /* 403 */ "Forbidden",             /* RFC7231, Section 6.5.3 */
-  /* 404 */ "Not Found",             /* RFC7231, Section 6.5.4 */
-  /* 405 */ "Method Not Allowed",    /* RFC7231, Section 6.5.5 */
-  /* 406 */ "Not Acceptable",        /* RFC7231, Section 6.5.6 */
-  /* 407 */ "Proxy Authentication Required", /* RFC7235, Section 3.2 */
-  /* 408 */ "Request Timeout",       /* RFC7231, Section 6.5.7 */
-  /* 409 */ "Conflict",              /* RFC7231, Section 6.5.8 */
-  /* 410 */ "Gone",                  /* RFC7231, Section 6.5.9 */
-  /* 411 */ "Length Required",       /* RFC7231, Section 6.5.10 */
-  /* 412 */ "Precondition Failed",   /* RFC7232, Section 4.2; RFC8144, Section 
3.2 */
-  /* 413 */ "Payload Too Large",     /* RFC7231, Section 6.5.11 */
-  /* 414 */ "URI Too Long",          /* RFC7231, Section 6.5.12 */
-  /* 415 */ "Unsupported Media Type", /* RFC7231, Section 6.5.13; RFC7694, 
Section 3 */
-  /* 416 */ "Range Not Satisfiable", /* RFC7233, Section 4.4 */
-  /* 417 */ "Expectation Failed",    /* RFC7231, Section 6.5.14 */
-  /* 418 */ "Unknown",               /* Not used */
-  /* 419 */ "Unknown",               /* Not used */
-  /* 420 */ "Unknown",               /* Not used */
-  /* 421 */ "Misdirected Request",   /* RFC7540, Section 9.1.2 */
-  /* 422 */ "Unprocessable Entity",  /* RFC4918 */
-  /* 423 */ "Locked",                /* RFC4918 */
-  /* 424 */ "Failed Dependency",     /* RFC4918 */
-  /* 425 */ "Too Early",             /* RFC8470 */
-  /* 426 */ "Upgrade Required",      /* RFC7231, Section 6.5.15 */
-  /* 427 */ "Unknown",               /* Not used */
-  /* 428 */ "Precondition Required", /* RFC6585 */
-  /* 429 */ "Too Many Requests",     /* RFC6585 */
-  /* 430 */ "Unknown",               /* Not used */
-  /* 431 */ "Request Header Fields Too Large", /* RFC6585 */
-  /* 432 */ "Unknown",               /* Not used */
-  /* 433 */ "Unknown",               /* Not used */
-  /* 434 */ "Unknown",               /* Not used */
-  /* 435 */ "Unknown",               /* Not used */
-  /* 436 */ "Unknown",               /* Not used */
-  /* 437 */ "Unknown",               /* Not used */
-  /* 438 */ "Unknown",               /* Not used */
-  /* 439 */ "Unknown",               /* Not used */
-  /* 440 */ "Unknown",               /* Not used */
-  /* 441 */ "Unknown",               /* Not used */
-  /* 442 */ "Unknown",               /* Not used */
-  /* 443 */ "Unknown",               /* Not used */
-  /* 444 */ "Unknown",               /* Not used */
-  /* 445 */ "Unknown",               /* Not used */
-  /* 446 */ "Unknown",               /* Not used */
-  /* 447 */ "Unknown",               /* Not used */
-  /* 448 */ "Unknown",               /* Not used */
-  /* 449 */ "Reply With",            /* MS IIS extension */
-  /* 450 */ "Blocked by Windows Parental Controls", /* MS extension */
-  /* 451 */ "Unavailable For Legal Reasons" /* RFC7725 */
+static const struct _MHD_str_w_len four_hundred[] = {
+  /* 400 */ _MHD_S_STR_W_LEN ("Bad Request"),    /* RFC7231, Section 6.5.1 */
+  /* 401 */ _MHD_S_STR_W_LEN ("Unauthorized"),   /* RFC7235, Section 3.1 */
+  /* 402 */ _MHD_S_STR_W_LEN ("Payment Required"), /* RFC7231, Section 6.5.2 */
+  /* 403 */ _MHD_S_STR_W_LEN ("Forbidden"),      /* RFC7231, Section 6.5.3 */
+  /* 404 */ _MHD_S_STR_W_LEN ("Not Found"),      /* RFC7231, Section 6.5.4 */
+  /* 405 */ _MHD_S_STR_W_LEN ("Method Not Allowed"), /* RFC7231, Section 6.5.5 
*/
+  /* 406 */ _MHD_S_STR_W_LEN ("Not Acceptable"), /* RFC7231, Section 6.5.6 */
+  /* 407 */ _MHD_S_STR_W_LEN ("Proxy Authentication Required"), /* RFC7235, 
Section 3.2 */
+  /* 408 */ _MHD_S_STR_W_LEN ("Request Timeout"), /* RFC7231, Section 6.5.7 */
+  /* 409 */ _MHD_S_STR_W_LEN ("Conflict"),       /* RFC7231, Section 6.5.8 */
+  /* 410 */ _MHD_S_STR_W_LEN ("Gone"),           /* RFC7231, Section 6.5.9 */
+  /* 411 */ _MHD_S_STR_W_LEN ("Length Required"), /* RFC7231, Section 6.5.10 */
+  /* 412 */ _MHD_S_STR_W_LEN ("Precondition Failed"), /* RFC7232, Section 4.2; 
RFC8144, Section 3.2 */
+  /* 413 */ _MHD_S_STR_W_LEN ("Payload Too Large"), /* RFC7231, Section 6.5.11 
*/
+  /* 414 */ _MHD_S_STR_W_LEN ("URI Too Long"),   /* RFC7231, Section 6.5.12 */
+  /* 415 */ _MHD_S_STR_W_LEN ("Unsupported Media Type"), /* RFC7231, Section 
6.5.13; RFC7694, Section 3 */
+  /* 416 */ _MHD_S_STR_W_LEN ("Range Not Satisfiable"), /* RFC7233, Section 
4.4 */
+  /* 417 */ _MHD_S_STR_W_LEN ("Expectation Failed"), /* RFC7231, Section 
6.5.14 */
+  /* 418 */ {"Unknown", 0},                      /* Not used */
+  /* 419 */ {"Unknown", 0},                      /* Not used */
+  /* 420 */ {"Unknown", 0},                      /* Not used */
+  /* 421 */ _MHD_S_STR_W_LEN ("Misdirected Request"), /* RFC7540, Section 
9.1.2 */
+  /* 422 */ _MHD_S_STR_W_LEN ("Unprocessable Entity"), /* RFC4918 */
+  /* 423 */ _MHD_S_STR_W_LEN ("Locked"),         /* RFC4918 */
+  /* 424 */ _MHD_S_STR_W_LEN ("Failed Dependency"), /* RFC4918 */
+  /* 425 */ _MHD_S_STR_W_LEN ("Too Early"),      /* RFC8470 */
+  /* 426 */ _MHD_S_STR_W_LEN ("Upgrade Required"), /* RFC7231, Section 6.5.15 
*/
+  /* 427 */ {"Unknown", 0},                      /* Not used */
+  /* 428 */ _MHD_S_STR_W_LEN ("Precondition Required"), /* RFC6585 */
+  /* 429 */ _MHD_S_STR_W_LEN ("Too Many Requests"), /* RFC6585 */
+  /* 430 */ {"Unknown", 0},                      /* Not used */
+  /* 431 */ _MHD_S_STR_W_LEN ("Request Header Fields Too Large"), /* RFC6585 */
+  /* 432 */ {"Unknown", 0},                      /* Not used */
+  /* 433 */ {"Unknown", 0},                      /* Not used */
+  /* 434 */ {"Unknown", 0},                      /* Not used */
+  /* 435 */ {"Unknown", 0},                      /* Not used */
+  /* 436 */ {"Unknown", 0},                      /* Not used */
+  /* 437 */ {"Unknown", 0},                      /* Not used */
+  /* 438 */ {"Unknown", 0},                      /* Not used */
+  /* 439 */ {"Unknown", 0},                      /* Not used */
+  /* 440 */ {"Unknown", 0},                      /* Not used */
+  /* 441 */ {"Unknown", 0},                      /* Not used */
+  /* 442 */ {"Unknown", 0},                      /* Not used */
+  /* 443 */ {"Unknown", 0},                      /* Not used */
+  /* 444 */ {"Unknown", 0},                      /* Not used */
+  /* 445 */ {"Unknown", 0},                      /* Not used */
+  /* 446 */ {"Unknown", 0},                      /* Not used */
+  /* 447 */ {"Unknown", 0},                      /* Not used */
+  /* 448 */ {"Unknown", 0},                      /* Not used */
+  /* 449 */ _MHD_S_STR_W_LEN ("Reply With"),     /* MS IIS extension */
+  /* 450 */ _MHD_S_STR_W_LEN ("Blocked by Windows Parental Controls"), /* MS 
extension */
+  /* 451 */ _MHD_S_STR_W_LEN ("Unavailable For Legal Reasons") /* RFC7725 */
 };
 
-static const char *const five_hundred[] = {
-  /* 500 */ "Internal Server Error", /* RFC7231, Section 6.6.1 */
-  /* 501 */ "Not Implemented",       /* RFC7231, Section 6.6.2 */
-  /* 502 */ "Bad Gateway",           /* RFC7231, Section 6.6.3 */
-  /* 503 */ "Service Unavailable",   /* RFC7231, Section 6.6.4 */
-  /* 504 */ "Gateway Timeout",       /* RFC7231, Section 6.6.5 */
-  /* 505 */ "HTTP Version Not Supported", /* RFC7231, Section 6.6.6 */
-  /* 506 */ "Variant Also Negotiates", /* RFC2295 */
-  /* 507 */ "Insufficient Storage",  /* RFC4918 */
-  /* 508 */ "Loop Detected",         /* RFC5842 */
-  /* 509 */ "Bandwidth Limit Exceeded", /* Apache extension */
-  /* 510 */ "Not Extended",          /* RFC2774 */
-  /* 511 */ "Network Authentication Required" /* RFC6585 */
+static const struct _MHD_str_w_len five_hundred[] = {
+  /* 500 */ _MHD_S_STR_W_LEN ("Internal Server Error"), /* RFC7231, Section 
6.6.1 */
+  /* 501 */ _MHD_S_STR_W_LEN ("Not Implemented"), /* RFC7231, Section 6.6.2 */
+  /* 502 */ _MHD_S_STR_W_LEN ("Bad Gateway"),    /* RFC7231, Section 6.6.3 */
+  /* 503 */ _MHD_S_STR_W_LEN ("Service Unavailable"), /* RFC7231, Section 
6.6.4 */
+  /* 504 */ _MHD_S_STR_W_LEN ("Gateway Timeout"), /* RFC7231, Section 6.6.5 */
+  /* 505 */ _MHD_S_STR_W_LEN ("HTTP Version Not Supported"), /* RFC7231, 
Section 6.6.6 */
+  /* 506 */ _MHD_S_STR_W_LEN ("Variant Also Negotiates"), /* RFC2295 */
+  /* 507 */ _MHD_S_STR_W_LEN ("Insufficient Storage"), /* RFC4918 */
+  /* 508 */ _MHD_S_STR_W_LEN ("Loop Detected"),  /* RFC5842 */
+  /* 509 */ _MHD_S_STR_W_LEN ("Bandwidth Limit Exceeded"), /* Apache extension 
*/
+  /* 510 */ _MHD_S_STR_W_LEN ("Not Extended"),   /* RFC2774 */
+  /* 511 */ _MHD_S_STR_W_LEN ("Network Authentication Required") /* RFC6585 */
 };
 
 
 struct MHD_Reason_Block
 {
   size_t max;
-  const char *const*data;
+  const struct _MHD_str_w_len *const data;
 };
 
-#define BLOCK(m) { (sizeof(m) / sizeof(char*)), m }
+#define BLOCK(m) { (sizeof(m) / sizeof(m[0])), m }
 
 static const struct MHD_Reason_Block reasons[] = {
   BLOCK (invalid_hundred),
@@ -179,6 +180,17 @@ MHD_get_reason_phrase_for (unsigned int code)
   if ( (code >= 100) &&
        (code < 600) &&
        (reasons[code / 100].max > (code % 100)) )
-    return reasons[code / 100].data[code % 100];
+    return reasons[code / 100].data[code % 100].str;
   return "Unknown";
 }
+
+
+size_t
+MHD_get_reason_phrase_len_for (unsigned int code)
+{
+  if ( (code >= 100) &&
+       (code < 600) &&
+       (reasons[code / 100].max > (code % 100)) )
+    return reasons[code / 100].data[code % 100].len;
+  return 0;
+}
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c
index f502187f..c7cfd086 100644
--- a/src/microhttpd/response.c
+++ b/src/microhttpd/response.c
@@ -208,9 +208,10 @@ static enum MHD_Result
 add_response_header_connection (struct MHD_Response *response,
                                 const char *value)
 {
-  static const char *key = "Connection";
+  static const char *key = MHD_HTTP_HEADER_CONNECTION;
   /** the length of the "Connection" key */
-  static const size_t key_len = MHD_STATICSTR_LEN_ ("Connection");
+  static const size_t key_len =
+    MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONNECTION);
   size_t value_len;  /**< the length of the @a value */
   size_t old_value_len; /**< the length of the existing "Connection" value */
   size_t buf_size;   /**< the size of the buffer */
@@ -373,8 +374,10 @@ del_response_header_connection (struct MHD_Response 
*response,
 {
   struct MHD_HTTP_Header *hdr; /**< existing "Connection" header */
 
-  hdr = MHD_get_response_element_n_ (response, MHD_HEADER_KIND, "Connection",
-                                     MHD_STATICSTR_LEN_ ("Connection"));
+  hdr = MHD_get_response_element_n_ (response, MHD_HEADER_KIND,
+                                     MHD_HTTP_HEADER_CONNECTION,
+                                     MHD_STATICSTR_LEN_ ( \
+                                       MHD_HTTP_HEADER_CONNECTION));
   if (NULL == hdr)
     return MHD_NO;
 
@@ -468,9 +471,23 @@ MHD_add_response_header (struct MHD_Response *response,
        "chunked" is not allowed.  Note that MHD will set the
        correct transfer encoding if required automatically. */
     /* NOTE: for compressed bodies, use the "Content-encoding" header */
-    if ( (! MHD_str_equal_caseless_ (content, "identity")) &&
-         (! MHD_str_equal_caseless_ (content, "chunked")) )
-      return MHD_NO;
+    if (MHD_str_equal_caseless_ (content, "identity"))
+      return add_response_entry (response,
+                                 MHD_HEADER_KIND,
+                                 header,
+                                 content);
+    else if (MHD_str_equal_caseless_ (content, "chunked"))
+    {
+      if (MHD_NO != add_response_entry (response,
+                                        MHD_HEADER_KIND,
+                                        header,
+                                        content))
+      {
+        response->flags_auto |= MHD_RAF_HAS_TRANS_ENC_CHUNKED;
+        return MHD_YES;
+      }
+    }
+    return MHD_NO;
   }
   if ( (0 == (MHD_RF_INSANITY_HEADER_CONTENT_LENGTH
               & response->flags)) &&
@@ -534,8 +551,9 @@ MHD_del_response_header (struct MHD_Response *response,
   header_len = strlen (header);
 
   if ((0 != (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR)) &&
-      (MHD_STATICSTR_LEN_ ("Connection") == header_len) &&
-      MHD_str_equal_caseless_bin_n_ (header, "Connection", header_len))
+      (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONNECTION) == header_len) &&
+      MHD_str_equal_caseless_bin_n_ (header, MHD_HTTP_HEADER_CONNECTION,
+                                     header_len))
     return del_response_header_connection (response, content);
 
   content_len = strlen (content);
@@ -555,6 +573,12 @@ MHD_del_response_header (struct MHD_Response *response,
       free (pos->header);
       free (pos->value);
       free (pos);
+      if ( (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_TRANSFER_ENCODING) ==
+            header_len) &&
+           MHD_str_equal_caseless_bin_n_ (header,
+                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
+                                          header_len) )
+        response->flags_auto &= ~(MHD_RAF_HAS_TRANS_ENC_CHUNKED);
       return MHD_YES;
     }
     pos = pos->next;
diff --git a/src/microhttpd/test_http_reasons.c 
b/src/microhttpd/test_http_reasons.c
index 7c2c3efd..b648c3b0 100644
--- a/src/microhttpd/test_http_reasons.c
+++ b/src/microhttpd/test_http_reasons.c
@@ -1,6 +1,6 @@
 /*
   This file is part of libmicrohttpd
-  Copyright (C) 2017 Karlson2k (Evgeny Grin)
+  Copyright (C) 2017-2021 Karlson2k (Evgeny Grin)
 
   This test tool is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -25,18 +25,36 @@
 
 #include "mhd_options.h"
 #include <stdio.h>
+#include <string.h>
 #include "microhttpd.h"
 #include "mhd_str.h"
 
+static const char *const r_unknown = "unknown";
+
 static int
-expect_result (int code, const char*expected)
+expect_result (int code, const char *expected)
 {
-  const char*const reason = MHD_get_reason_phrase_for (code);
-  if (MHD_str_equal_caseless_ (reason, expected))
+  const char *const reason = MHD_get_reason_phrase_for (code);
+  const size_t len = MHD_get_reason_phrase_len_for (code);
+  size_t exp_len;
+  if (! MHD_str_equal_caseless_ (reason, expected))
+  {
+    fprintf (stderr,
+             "Incorrect reason returned for code %d:\n  Returned: \"%s\"  
\tExpected: \"%s\"\n",
+             code, reason, expected);
+    return 0;
+  }
+  if (r_unknown == expected)
+    exp_len = 0;
+  else
+    exp_len = strlen (expected);
+  if (exp_len != len)
+  {
+    fprintf (stderr,
+             "Incorrect reason length returned for code %d:\n  Returned: 
\"%u\"  \tExpected: \"%u\"\n",
+             code, (unsigned) len, (unsigned) exp_len);
     return 0;
-  fprintf (stderr,
-           "Incorrect reason returned for code %d:\n  Returned: \"%s\"  
\tExpected: \"%s\"\n",
-           code, reason, expected);
+  }
   return 1;
 }
 
@@ -44,7 +62,7 @@ expect_result (int code, const char*expected)
 static int
 expect_absent (int code)
 {
-  return expect_result (code, "unknown");
+  return expect_result (code, r_unknown);
 }
 
 
diff --git a/src/microhttpd/test_str.c b/src/microhttpd/test_str.c
index 1e140cb6..81ba378f 100644
--- a/src/microhttpd/test_str.c
+++ b/src/microhttpd/test_str.c
@@ -3314,6 +3314,313 @@ run_str_to_X_tests (void)
 }
 
 
+int
+check_str_from_uint16 (void)
+{
+  size_t t_failed = 0;
+  size_t i, j;
+  char buf[70];
+  const char *erase =
+    "-@=sd#+&(pdiren456qwe#@C3S!DAS45AOIPUQWESAdFzxcv1s*()&#$%34`"
+    "32452d098poiden45SADFFDA3S4D3SDFdfgsdfgsSADFzxdvs$*()&#2342`"
+    "adsf##$$@&*^%*^&56qwe#3C@S!DAScFAOIP$#%#$Ad1zs3v1$*()&#1228`";
+  static const size_t n_checks = sizeof(dstrs_w_values)
+                                 / sizeof(dstrs_w_values[0]);
+  int c_failed[n_checks];
+
+  memset (c_failed, 0, sizeof(c_failed));
+
+  for (j = 0; j < locale_name_count; j++)
+  {
+    set_test_locale (j);  /* setlocale() can be slow! */
+    for (i = 0; i < n_checks; i++)
+    {
+      const struct str_with_value *const t = dstrs_w_values + i;
+      size_t b_size;
+      size_t rs;
+
+      if (c_failed[i])
+        continue;     /* skip already failed checks */
+
+      if (t->str.len < t->num_of_digt)
+      {
+        fprintf (stderr,
+                 "ERROR: dstrs_w_values[%u] has wrong num_of_digt (%u): 
num_of_digt is expected"
+                 " to be less or equal to str.len (%u).\n",
+                 (unsigned int) i, (unsigned int) t->num_of_digt, (unsigned
+                                                                   int) t->str.
+                 len);
+        return -1;
+      }
+      if ('0' == t->str.str[0])
+        continue;  /* Skip strings prefixed with zeros */
+      if (t->num_of_digt != t->str.len)
+        continue;  /* Skip strings with suffixes */
+      if (UINT16_MAX < t->val)
+        continue;  /* Too large value to convert */
+      if (sizeof(buf) < t->str.len + 1)
+      {
+        fprintf (stderr,
+                 "ERROR: dstrs_w_values[%u] has too long (%u) string, "
+                 "size of 'buf' should be increased.\n",
+                 (unsigned int) i, (unsigned int) t->str.len);
+        return -1;
+      }
+      for (b_size = 0; b_size <= t->str.len + 1; ++b_size)
+      {
+        /* fill buffer with pseudo-random values */
+        memcpy (buf, erase, sizeof(buf));
+
+        rs = MHD_uint16_to_str (t->val, buf, b_size);
+
+        if (t->num_of_digt > b_size)
+        {
+          /* Must fail, buffer is too small for result */
+          if (0 != rs)
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> buf,"
+                     " %d) returned %" PRIuPTR
+                     ", while expecting 0."
+                     " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs,
+                     get_current_locale_str ());
+          }
+        }
+        else
+        {
+          if (t->num_of_digt != rs)
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> buf,"
+                     " %d) returned %" PRIuPTR
+                     ", while expecting %d."
+                     " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs,
+                     (int) t->num_of_digt, get_current_locale_str ());
+          }
+          else if (0 != memcmp (buf, t->str.str, t->num_of_digt))
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> \"%.*s\","
+                     " %d) returned %" PRIuPTR "."
+                     " Locale: %s\n", t->val, (int) rs, buf, (int) b_size,
+                     (intptr_t) rs,  get_current_locale_str ());
+          }
+          else if (0 != memcmp (buf + rs, erase + rs, sizeof(buf) - rs))
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> \"%.*s\","
+                     " %d) returned %" PRIuPTR
+                     " and touched data after the resulting string."
+                     " Locale: %s\n", t->val, (int) rs, buf, (int) b_size,
+                     (intptr_t) rs,  get_current_locale_str ());
+          }
+        }
+      }
+      if ((verbose > 1) && (j == locale_name_count - 1) && ! c_failed[i])
+        printf ("PASSED: MHD_uint16_to_str(%" PRIu64 ", -> \"%.*s\", %d) "
+                "== %" PRIuPTR "\n",
+                t->val, (int) rs, buf, (int) b_size - 1, (intptr_t) rs);
+    }
+  }
+  return t_failed;
+}
+
+
+int
+check_strx_from_uint32 (void)
+{
+  size_t t_failed = 0;
+  size_t i, j;
+  char buf[70];
+  const char *erase =
+    "jrlkjssfhjfvrjntJHLJ$@%$#adsfdkj;k$##$%#$%FGDF%$#^FDFG%$#$D`"
+    ";skjdhjflsdkjhdjfalskdjhdfalkjdhf$%##%$$#%FSDGFSDDGDFSSDSDF`"
+    "#5#$%#$#$DFSFDDFSGSDFSDF354FDDSGFDFfdssfddfswqemn,.zxih,.sx`";
+  static const size_t n_checks = sizeof(xdstrs_w_values)
+                                 / sizeof(xdstrs_w_values[0]);
+  int c_failed[n_checks];
+
+  memset (c_failed, 0, sizeof(c_failed));
+
+  for (j = 0; j < locale_name_count; j++)
+  {
+    set_test_locale (j);  /* setlocale() can be slow! */
+    for (i = 0; i < n_checks; i++)
+    {
+      const struct str_with_value *const t = xdstrs_w_values + i;
+      size_t b_size;
+      size_t rs;
+
+      if (c_failed[i])
+        continue;     /* skip already failed checks */
+
+      if (t->str.len < t->num_of_digt)
+      {
+        fprintf (stderr,
+                 "ERROR: dstrs_w_values[%u] has wrong num_of_digt (%u): 
num_of_digt is expected"
+                 " to be less or equal to str.len (%u).\n",
+                 (unsigned int) i, (unsigned int) t->num_of_digt, (unsigned
+                                                                   int) t->str.
+                 len);
+        return -1;
+      }
+      if ('0' == t->str.str[0])
+        continue;  /* Skip strings prefixed with zeros */
+      if (t->num_of_digt != t->str.len)
+        continue;  /* Skip strings with suffixes */
+      if (UINT32_MAX < t->val)
+        continue;  /* Too large value to convert */
+      if (sizeof(buf) < t->str.len + 1)
+      {
+        fprintf (stderr,
+                 "ERROR: dstrs_w_values[%u] has too long (%u) string, "
+                 "size of 'buf' should be increased.\n",
+                 (unsigned int) i, (unsigned int) t->str.len);
+        return -1;
+      }
+      for (b_size = 0; b_size <= t->str.len + 1; ++b_size)
+      {
+        /* fill buffer with pseudo-random values */
+        memcpy (buf, erase, sizeof(buf));
+
+        rs = MHD_uint32_to_strx (t->val, buf, b_size);
+
+        if (t->num_of_digt > b_size)
+        {
+          /* Must fail, buffer is too small for result */
+          if (0 != rs)
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> buf,"
+                     " %d) returned %" PRIuPTR
+                     ", while expecting 0."
+                     " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs,
+                     get_current_locale_str ());
+          }
+        }
+        else
+        {
+          if (t->num_of_digt != rs)
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> buf,"
+                     " %d) returned %" PRIuPTR
+                     ", while expecting %d."
+                     " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs,
+                     (int) t->num_of_digt, get_current_locale_str ());
+          }
+          else if (0 == MHD_str_equal_caseless_bin_n_ (buf, t->str.str,
+                                                       t->num_of_digt))
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> \"%.*s\","
+                     " %d) returned %" PRIuPTR "."
+                     " Locale: %s\n", t->val, (int) rs, buf, (int) b_size,
+                     (intptr_t) rs,  get_current_locale_str ());
+          }
+          else if (0 != memcmp (buf + rs, erase + rs, sizeof(buf) - rs))
+          {
+            if (0 == c_failed[i])
+              t_failed++;
+            c_failed[i] = ! 0;
+            fprintf (stderr,
+                     "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> \"%.*s\","
+                     " %d) returned %" PRIuPTR
+                     " and touched data after the resulting string."
+                     " Locale: %s\n", t->val, (int) rs, buf, (int) b_size,
+                     (intptr_t) rs,  get_current_locale_str ());
+          }
+        }
+      }
+      if ((verbose > 1) && (j == locale_name_count - 1) && ! c_failed[i])
+        printf ("PASSED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> \"%.*s\", %d) "
+                "== %" PRIuPTR "\n",
+                t->val, (int) rs, buf, (int) b_size - 1, (intptr_t) rs);
+    }
+  }
+  return t_failed;
+}
+
+
+int
+run_str_from_X_tests (void)
+{
+  int str_from_uint16;
+  int strx_from_uint32;
+  int failures;
+
+  failures = 0;
+
+  str_from_uint16 = check_str_from_uint16 ();
+  if (str_from_uint16 != 0)
+  {
+    if (str_from_uint16 < 0)
+    {
+      fprintf (stderr,
+               "ERROR: test internal error in check_str_from_uint16().\n");
+      return 99;
+    }
+    fprintf (stderr,
+             "FAILED: testcase check_str_from_uint16() failed.\n\n");
+    failures += str_from_uint16;
+  }
+  else if (verbose > 1)
+    printf (
+      "PASSED: testcase check_str_from_uint16() successfully passed.\n\n");
+
+  strx_from_uint32 = check_strx_from_uint32 ();
+  if (strx_from_uint32 != 0)
+  {
+    if (strx_from_uint32 < 0)
+    {
+      fprintf (stderr,
+               "ERROR: test internal error in check_strx_from_uint32().\n");
+      return 99;
+    }
+    fprintf (stderr,
+             "FAILED: testcase check_strx_from_uint32() failed.\n\n");
+    failures += strx_from_uint32;
+  }
+  else if (verbose > 1)
+    printf (
+      "PASSED: testcase check_strx_from_uint32() successfully passed.\n\n");
+
+  if (failures)
+  {
+    if (verbose > 0)
+      printf ("At least one test failed.\n");
+
+    return 1;
+  }
+
+  if (verbose > 0)
+    printf ("All tests passed successfully.\n");
+
+  return 0;
+}
+
+
 int
 main (int argc, char *argv[])
 {
@@ -3328,5 +3635,8 @@ main (int argc, char *argv[])
   if (has_in_name (argv[0], "_to_value"))
     return run_str_to_X_tests ();
 
+  if (has_in_name (argv[0], "_from_value"))
+    return run_str_from_X_tests ();
+
   return run_eq_neq_str_tests ();
 }

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