gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (56c4b4ae -> 8d5ebaec)


From: gnunet
Subject: [libmicrohttpd] branch master updated (56c4b4ae -> 8d5ebaec)
Date: Mon, 06 Jun 2022 18:41:26 +0200

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 56c4b4ae test_auth_parse: added more checks with unclose quotation for 
digest auth
     new b587bb72 test_auth_parse: minor formatting imrpovement
     new 667be90d mhd_str: fixed doxy again
     new 83d7386c MHD_str_equal_quoted_bin_n(): added new internal function
     new d9c37e01 test_str_quote: added new test
     new 7eef6dd3 Excluded build on the new string functions when they are 
unused
     new 1a37de96 MHD_str_equal_caseless_quoted_bin_n(): added new internal 
function
     new 1e010db7 test_str_quote: added testing of the new function
     new eb48c258 Simplified Digest Auth code by using the new string 
processing functions
     new d9ebd051 digestauth: avoid repetitive calculations of some strings' 
length
     new 8d5ebaec gen_auth: simplified value assignment

The 10 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/microhttpd/.gitignore        |   1 +
 src/microhttpd/Makefile.am       |   9 +-
 src/microhttpd/basicauth.h       |   2 +-
 src/microhttpd/digestauth.c      | 111 ++++---
 src/microhttpd/digestauth.h      |   2 +-
 src/microhttpd/gen_auth.c        |  49 +--
 src/microhttpd/mhd_str.c         |  64 ++++
 src/microhttpd/mhd_str.h         |  68 +++-
 src/microhttpd/test_auth_parse.c |   6 +-
 src/microhttpd/test_str_quote.c  | 681 +++++++++++++++++++++++++++++++++++++++
 10 files changed, 903 insertions(+), 90 deletions(-)
 create mode 100644 src/microhttpd/test_str_quote.c

diff --git a/src/microhttpd/.gitignore b/src/microhttpd/.gitignore
index a0c66b93..d7050119 100644
--- a/src/microhttpd/.gitignore
+++ b/src/microhttpd/.gitignore
@@ -79,3 +79,4 @@ test_postprocessor_md
 /test_client_put_chunked_steps_hard_close
 /test_set_panic
 /test_auth_parse
+/test_str_quote
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index b7bae34c..f6e1e2bd 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -260,6 +260,10 @@ if HAVE_ANYAUTH
 check_PROGRAMS += \
   test_auth_parse
 endif
+if ENABLE_DAUTH
+check_PROGRAMS += \
+  test_str_quote
+endif
 
 TESTS = $(check_PROGRAMS)
 
@@ -435,7 +439,10 @@ test_sha1_SOURCES = \
   sha1.c sha1.h mhd_bithelpers.h mhd_byteorder.h mhd_align.h
 
 test_auth_parse_SOURCES = \
-  test_auth_parse.c gen_auth.c gen_auth.h  mhd_str.h mhd_str.c
+  test_auth_parse.c gen_auth.c gen_auth.h  mhd_str.h mhd_str.c mhd_assert.h
+  
+test_str_quote_SOURCES = \
+  test_str_quote.c mhd_str.h mhd_str.c mhd_assert.h
 
 test_options_SOURCES = \
   test_options.c
diff --git a/src/microhttpd/basicauth.h b/src/microhttpd/basicauth.h
index c46fe27a..e0bbeec5 100644
--- a/src/microhttpd/basicauth.h
+++ b/src/microhttpd/basicauth.h
@@ -37,7 +37,7 @@
 
 struct MHD_RqBAuth
 {
-  struct _MHD_cstr_w_len token68;
+  struct _MHD_str_w_len token68;
 };
 
 #endif /* ! MHD_BASICAUTH_H */
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index d94da65e..c3717d47 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -485,7 +485,9 @@ digest_calc_ha1_from_digest (const char *alg,
  * @param alg The hash algorithm used, can be "MD5" or "MD5-sess"
  *             or "SHA-256" or "SHA-256-sess"
  * @param username A `char *' pointer to the username value
+ * @param username the length of the @a username
  * @param realm A `char *' pointer to the realm value
+ * @param realm_len the length of the @a realm
  * @param password A `char *' pointer to the password value
  * @param nonce A `char *' pointer to the nonce value
  * @param cnonce A `char *' pointer to the cnonce value
@@ -495,7 +497,9 @@ digest_calc_ha1_from_digest (const char *alg,
 static void
 digest_calc_ha1_from_user (const char *alg,
                            const char *username,
+                           size_t username_len,
                            const char *realm,
+                           size_t realm_len,
                            const char *password,
                            const char *nonce,
                            const char *cnonce,
@@ -504,13 +508,13 @@ digest_calc_ha1_from_user (const char *alg,
   digest_init (da);
   digest_update (da,
                  (const unsigned char *) username,
-                 strlen (username));
+                 username_len);
   digest_update (da,
                  (const unsigned char *) ":",
                  1);
   digest_update (da,
                  (const unsigned char *) realm,
-                 strlen (realm));
+                 realm_len);
   digest_update (da,
                  (const unsigned char *) ":",
                  1);
@@ -914,6 +918,7 @@ MHD_digest_auth_get_username (struct MHD_Connection 
*connection)
  * @param rnd_size The size of the random seed array @a rnd
  * @param uri HTTP URI (in MHD, without the arguments ("?k=v")
  * @param realm A string of characters that describes the realm of auth.
+ * @param realm_len the length of the @a realm.
  * @param da digest algorithm to use
  * @param[out] nonce A pointer to a character array for the nonce to put in,
  *        must provide NONCE_STD_LEN(da->digest_size)+1 bytes
@@ -925,6 +930,7 @@ calculate_nonce (uint64_t nonce_time,
                  size_t rnd_size,
                  const char *uri,
                  const char *realm,
+                 size_t realm_len,
                  struct DigestAlgorithm *da,
                  char *nonce)
 {
@@ -969,7 +975,7 @@ calculate_nonce (uint64_t nonce_time,
                  1);
   digest_update (da,
                  (const unsigned char *) realm,
-                 strlen (realm));
+                 realm_len);
   digest_calc_hash (da);
   MHD_bin_to_hex (digest_get_bin (da),
                   digest_get_size (da),
@@ -1045,6 +1051,7 @@ is_slot_available (const struct MHD_NonceNc *const nn,
  * @param connection the MHD connection structure
  * @param timestamp the current timestamp
  * @param realm the string of characters that describes the realm of auth
+ * @param realm_len the lenght of the @a realm
  * @param da the digest algorithm to use
  * @param[out] nonce the pointer to a character array for the nonce to put in,
  *        must provide NONCE_STD_LEN(da->digest_size)+1 bytes
@@ -1055,6 +1062,7 @@ static bool
 calculate_add_nonce (struct MHD_Connection *const connection,
                      uint64_t timestamp,
                      const char *realm,
+                     size_t realm_len,
                      struct DigestAlgorithm *da,
                      char *nonce)
 {
@@ -1072,6 +1080,7 @@ calculate_add_nonce (struct MHD_Connection *const 
connection,
                    daemon->digest_auth_rand_size,
                    connection->url,
                    realm,
+                   realm_len,
                    da,
                    nonce);
 
@@ -1118,8 +1127,10 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
                                 char *nonce)
 {
   const uint64_t timestamp1 = MHD_monotonic_msec_counter ();
+  const size_t realm_len = strlen (realm);
 
-  if (! calculate_add_nonce (connection, timestamp1, realm, da, nonce))
+  if (! calculate_add_nonce (connection, timestamp1, realm, realm_len, da,
+                             nonce))
   {
     /* Either:
      * 1. The same nonce was already generated. If it will be used then one
@@ -1156,9 +1167,10 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
       /* Use up to 127 ms difference */
       timestamp2 -= (base4 & DAUTH_JUMPBACK_MAX);
       if (timestamp1 == timestamp2)
-        timestamp2 -= 2;
+        timestamp2 -= 2; /* Fallback value */
     }
-    if (! calculate_add_nonce (connection, timestamp2, realm, da, nonce2))
+    if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
+                               nonce2))
     {
       /* No free slot has been found. Re-tries are expensive, just use
        * the generated nonce. As it is not stored in nonce-nc map array,
@@ -1362,6 +1374,30 @@ get_unqouted_param (const struct MHD_RqDAuthParam *param,
 }
 
 
+/**
+ * Check whether Digest Auth request parameter is equal to given string
+ * @param param the parameter to check
+ * @param str the string to compare with, does not need to be zero-terminated
+ * @param str_len the length of the @a str
+ * @return true is parameter is equal to the given string,
+ *         false otherwise
+ */
+_MHD_static_inline bool
+is_param_equal (const struct MHD_RqDAuthParam *param,
+                const char *const str,
+                const size_t str_len)
+{
+  mhd_assert (NULL != param->value.str);
+  mhd_assert (0 != param->value.len);
+  if (param->quoted)
+    return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
+                                       str, str_len);
+  return (str_len == param->value.len) &&
+         (0 == memcmp (str, param->value.str, str_len));
+
+}
+
+
 /**
  * Authenticates the authorization header sent by the client
  *
@@ -1413,6 +1449,8 @@ digest_auth_check_all (struct MHD_Connection *connection,
 #ifdef HAVE_MESSAGES
   bool err_logged;
 #endif /* HAVE_MESSAGES */
+  size_t username_len;
+  size_t realm_len;
 
   tmp2 = NULL;
   tmp2_size = 0;
@@ -1420,35 +1458,24 @@ digest_auth_check_all (struct MHD_Connection 
*connection,
   err_logged = false;
 #endif /* HAVE_MESSAGES */
 
-  params = get_rq_dauth_params (connection);
-  if (NULL == params)
-    return MHD_DAUTH_WRONG_HEADER;
-
   do /* Only to avoid "goto" */
   {
+
+    params = get_rq_dauth_params (connection);
+    if (NULL == params)
+    {
+      ret = MHD_DAUTH_WRONG_HEADER;
+      break;
+    }
+
     /* Check 'username' */
-    unq_res = get_unqouted_param (&params->username, tmp1, &tmp2, &tmp2_size,
-                                  &unquoted);
-    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    if (NULL == params->username.value.str)
     {
-      if (_MHD_UNQ_NO_STRING == unq_res)
-        ret = MHD_DAUTH_WRONG_HEADER;
-      else if (_MHD_UNQ_EMPTY == unq_res)
-        ret = MHD_DAUTH_WRONG_USERNAME;
-      else if (_MHD_UNQ_TOO_LARGE == unq_res)
-        ret = MHD_DAUTH_WRONG_HEADER;
-      else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
-        ret = MHD_DAUTH_ERROR;
-      else
-      {
-        mhd_assert (0); /* Must not happen */
-        ret = MHD_DAUTH_ERROR;
-      }
+      ret = MHD_DAUTH_WRONG_HEADER;
       break;
     }
-    /* 'unquoted" may not contain binary zero */
-    if ( (0 != strncmp (username, unquoted.str, unquoted.len)) ||
-         (0 != username[unquoted.len]) )
+    username_len = strlen (username);
+    if (! is_param_equal (&params->username, username, username_len))
     {
       ret = MHD_DAUTH_WRONG_USERNAME;
       break;
@@ -1456,28 +1483,13 @@ digest_auth_check_all (struct MHD_Connection 
*connection,
     /* 'username' valid */
 
     /* Check 'realm' */
-    unq_res = get_unqouted_param (&params->realm, tmp1, &tmp2, &tmp2_size,
-                                  &unquoted);
-    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    if (NULL == params->realm.value.str)
     {
-      if (_MHD_UNQ_NO_STRING == unq_res)
-        ret = MHD_DAUTH_WRONG_HEADER;
-      else if (_MHD_UNQ_EMPTY == unq_res)
-        ret = MHD_DAUTH_WRONG_REALM;
-      else if (_MHD_UNQ_TOO_LARGE == unq_res)
-        ret = MHD_DAUTH_WRONG_HEADER;
-      else if (_MHD_UNQ_OUT_OF_MEM == unq_res)
-        ret = MHD_DAUTH_ERROR;
-      else
-      {
-        mhd_assert (0); /* Must not happen */
-        ret = MHD_DAUTH_ERROR;
-      }
+      ret = MHD_DAUTH_WRONG_HEADER;
       break;
     }
-    /* 'unquoted" may not contain binary zero */
-    if ( (0 != strncmp (realm, unquoted.str, unquoted.len)) ||
-         (0 != realm[unquoted.len]) )
+    realm_len = strlen (realm);
+    if (! is_param_equal (&params->realm, realm, realm_len))
     {
       ret = MHD_DAUTH_WRONG_REALM;
       break;
@@ -1534,6 +1546,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
                      daemon->digest_auth_rand_size,
                      connection->url,
                      realm,
+                     realm_len,
                      da,
                      noncehashexp);
     /*
@@ -1779,7 +1792,9 @@ digest_auth_check_all (struct MHD_Connection *connection,
       mhd_assert (NULL != password);   /* NULL == digest => password != NULL */
       digest_calc_ha1_from_user (digest_get_algo_name (da),
                                  username,
+                                 username_len,
                                  realm,
+                                 realm_len,
                                  password,
                                  noncehashexp,
                                  cnonce,
diff --git a/src/microhttpd/digestauth.h b/src/microhttpd/digestauth.h
index 77c7c402..367e8e01 100644
--- a/src/microhttpd/digestauth.h
+++ b/src/microhttpd/digestauth.h
@@ -51,7 +51,7 @@
 
 struct MHD_RqDAuthParam
 {
-  struct _MHD_cstr_w_len value;
+  struct _MHD_str_w_len value;
   bool quoted;
 };
 
diff --git a/src/microhttpd/gen_auth.c b/src/microhttpd/gen_auth.c
index e13d5578..67bd9dc6 100644
--- a/src/microhttpd/gen_auth.c
+++ b/src/microhttpd/gen_auth.c
@@ -91,8 +91,8 @@ parse_bauth_params (const char *str,
     else
     {
       /* No more data in the string, only single token68. */
-      const struct _MHD_cstr_w_len tkn = { str + token68_start, token68_len};
-      memcpy (&pbauth->token68, &tkn, sizeof(tkn));
+      pbauth->token68.str = str + token68_start;
+      pbauth->token68.len = token68_len;
     }
   }
   return true;
@@ -251,11 +251,8 @@ parse_dauth_params (const char *str,
 
         /* Have valid parameter name and value */
         mhd_assert (! quoted || 0 != value_len);
-        if (1)
-        {
-          const struct _MHD_cstr_w_len val = {str + value_start, value_len};
-          memcpy (&aparam->param->value, &val, sizeof(val));
-        }
+        aparam->param->value.str = str + value_start;
+        aparam->param->value.len = value_len;
         aparam->param->quoted = quoted;
 
         break; /* Found matching parameter name */
@@ -295,35 +292,19 @@ parse_dauth_params (const char *str,
   }
 
   /* Postprocess values */
-  if ((NULL != userhash.value.str) && (0 != userhash.value.len))
+  if (NULL != userhash.value.str)
   {
-    const char *param_str;
-    size_t param_len;
-    char buf[5 * 2]; /* 5 is the length of "false" (longer then "true") */
-    if (! userhash.quoted)
-    {
-      param_str = userhash.value.str;
-      param_len = userhash.value.len;
-    }
-    else
-    {
-      if (sizeof(buf) / sizeof(buf[0]) >= userhash.value.len)
-      {
-        param_len = MHD_str_unquote (userhash.value.str, userhash.value.len,
-                                     buf);
-        param_str = buf;
-      }
-      else
-      {
-        param_len = 0;
-        param_str = NULL; /* Actually not used */
-      }
-    }
-    if ((param_len == 4) && MHD_str_equal_caseless_bin_n_ (param_str, "true",
-                                                           4))
-      pdauth->userhash = true;
+    if (userhash.quoted)
+      pdauth->userhash =
+        MHD_str_equal_caseless_quoted_bin_n (userhash.value.str,
+                                             userhash.value.len,
+                                             "true",
+                                             MHD_STATICSTR_LEN_ ("true"));
     else
-      pdauth->userhash = false;
+      pdauth->userhash =
+        (MHD_STATICSTR_LEN_ ("true") == userhash.value.len) &&
+        (0 == memcmp (str, userhash.value.str, userhash.value.len));
+
   }
   else
     pdauth->userhash = false;
diff --git a/src/microhttpd/mhd_str.c b/src/microhttpd/mhd_str.c
index 7a337574..5829daa5 100644
--- a/src/microhttpd/mhd_str.c
+++ b/src/microhttpd/mhd_str.c
@@ -1387,6 +1387,67 @@ MHD_bin_to_hex (const void *bin,
 }
 
 
+#ifdef DAUTH_SUPPORT
+bool
+MHD_str_equal_quoted_bin_n (const char *quoted,
+                            size_t quoted_len,
+                            const char *unquoted,
+                            size_t unquoted_len)
+{
+  size_t i;
+  size_t j;
+  if (unquoted_len < quoted_len / 2)
+    return false;
+
+  j = 0;
+  for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
+  {
+    if ('\\' == quoted[i])
+    {
+      i++; /* Advance to the next character */
+      if (quoted_len == i)
+        return false; /* No character after escaping backslash */
+    }
+    if (quoted[i] != unquoted[j])
+      return false; /* Different characters */
+  }
+  if ((quoted_len != i) || (unquoted_len != j))
+    return false; /* The strings have different length */
+
+  return true;
+}
+
+
+bool
+MHD_str_equal_caseless_quoted_bin_n (const char *quoted,
+                                     size_t quoted_len,
+                                     const char *unquoted,
+                                     size_t unquoted_len)
+{
+  size_t i;
+  size_t j;
+  if (unquoted_len < quoted_len / 2)
+    return false;
+
+  j = 0;
+  for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
+  {
+    if ('\\' == quoted[i])
+    {
+      i++; /* Advance to the next character */
+      if (quoted_len == i)
+        return false; /* No character after escaping backslash */
+    }
+    if (! charsequalcaseless (quoted[i], unquoted[j]))
+      return false; /* Different characters */
+  }
+  if ((quoted_len != i) || (unquoted_len != j))
+    return false; /* The strings have different length */
+
+  return true;
+}
+
+
 size_t
 MHD_str_unquote (const char *quoted,
                  size_t quoted_len,
@@ -1410,3 +1471,6 @@ MHD_str_unquote (const char *quoted,
   }
   return w;
 }
+
+
+#endif /* DAUTH_SUPPORT */
diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h
index 8279afd1..67b2d044 100644
--- a/src/microhttpd/mhd_str.h
+++ b/src/microhttpd/mhd_str.h
@@ -63,6 +63,15 @@ struct _MHD_cstr_w_len
   const size_t len;
 };
 
+/**
+ * String with length
+ */
+struct _MHD_str_w_len
+{
+  const char *str;
+  size_t len;
+};
+
 /**
  * Static string initialiser for struct _MHD_str_w_len
  */
@@ -475,6 +484,58 @@ MHD_bin_to_hex (const void *bin,
                 size_t size,
                 char *hex);
 
+#ifdef DAUTH_SUPPORT
+/**
+ * Check two strings for equality, "unquoting" the first string from quoted
+ * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings.
+ *
+ * Null-termination for input stings is not required, binary zeros compared
+ * like other characters.
+ *
+ * @param quoted the quoted string to compare, must NOT include leading and
+ *               closing DQUOTE chars, does not need to be zero-terminated
+ * @param quoted_len the length in chars of the @a quoted string
+ * @param unquoted the unquoted string to compare, does not need to be
+ *                 zero-terminated
+ * @param unquoted_len the length in chars of the @a unquoted string
+ * @return zero if quoted form is broken (no character after the last escaping
+ *         backslash), zero if strings are not equal after unquoting of the
+ *         first string,
+ *         non-zero if two strings are equal after unquoting of the
+ *         first string.
+ */
+bool
+MHD_str_equal_quoted_bin_n (const char *quoted,
+                            size_t quoted_len,
+                            const char *unquoted,
+                            size_t unquoted_len);
+
+/**
+ * Check two strings for equality, "unquoting" the first string from quoted
+ * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings and
+ * ignoring case of US-ASCII letters.
+ *
+ * Null-termination for input stings is not required, binary zeros compared
+ * like other characters.
+ *
+ * @param quoted the quoted string to compare, must NOT include leading and
+ *               closing DQUOTE chars, does not need to be zero-terminated
+ * @param quoted_len the length in chars of the @a quoted string
+ * @param unquoted the unquoted string to compare, does not need to be
+ *                 zero-terminated
+ * @param unquoted_len the length in chars of the @a unquoted string
+ * @return zero if quoted form is broken (no character after the last escaping
+ *         backslash), zero if strings are not equal after unquoting of the
+ *         first string,
+ *         non-zero if two strings are caseless equal after unquoting of the
+ *         first string.
+ */
+bool
+MHD_str_equal_caseless_quoted_bin_n (const char *quoted,
+                                     size_t quoted_len,
+                                     const char *unquoted,
+                                     size_t unquoted_len);
+
 /**
  * Convert string from quoted to unquoted form as specified by
  * RFC7230#section-3.2.6 and RFC7694#quoted.strings.
@@ -483,15 +544,18 @@ MHD_bin_to_hex (const void *bin,
  *               DQUOTE chars, does not need to be zero-terminated
  * @param quoted_len the length in chars of the @a quoted string
  * @param[out] result the pointer to the buffer to put the result, must
- *                    be at least @a size character long. The result is NOT
+ *                    be at least @a size character long.May be modified even
+ *                    if @a quoted is invalid sequence. The result is NOT
  *                    zero-terminated.
  * @return The number of characters written to the output buffer,
  *         zero if last backslash is not followed by any character (or
- *         @a size is zero).
+ *         @a quoted_len is zero).
  */
 size_t
 MHD_str_unquote (const char *quoted,
                  size_t quoted_len,
                  char *result);
 
+#endif /* DAUTH_SUPPORT */
+
 #endif /* MHD_STR_H */
diff --git a/src/microhttpd/test_auth_parse.c b/src/microhttpd/test_auth_parse.c
index df1957c1..6f7ca5ed 100644
--- a/src/microhttpd/test_auth_parse.c
+++ b/src/microhttpd/test_auth_parse.c
@@ -18,7 +18,7 @@
 */
 
 /**
- * @file microhttpd/test_str_token.c
+ * @file microhttpd/test_auth_parse.c
  * @brief  Unit tests for request's 'Authorization" headers parsing
  * @author Karlson2k (Evgeny Grin)
  */
@@ -713,8 +713,8 @@ check_type (void)
   r += expect_result_type (1, "DigestBasic ", MHD_AUTHTYPE_UNKNOWN);
   r += expect_result_type (1, " DigestBasic", MHD_AUTHTYPE_UNKNOWN);
   r += expect_result_type (1, "DigestBasic" "a", MHD_AUTHTYPE_UNKNOWN);
-  r += expect_result_type (1, "Digest\0", MHD_AUTHTYPE_UNKNOWN);
-  r += expect_result_type (1, "\0Digest", MHD_AUTHTYPE_UNKNOWN);
+  r += expect_result_type (1, "Digest" "\0", MHD_AUTHTYPE_UNKNOWN);
+  r += expect_result_type (1, "\0" "Digest", MHD_AUTHTYPE_UNKNOWN);
   return r;
 }
 
diff --git a/src/microhttpd/test_str_quote.c b/src/microhttpd/test_str_quote.c
new file mode 100644
index 00000000..2c3d942f
--- /dev/null
+++ b/src/microhttpd/test_str_quote.c
@@ -0,0 +1,681 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2022 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
+  published by the Free Software Foundation; either version 2, or
+  (at your option) any later version.
+
+  This test tool is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+*/
+
+/**
+ * @file microhttpd/test_str_quote.c
+ * @brief  Unit tests for quoted strings processing
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_options.h"
+#include <string.h>
+#include <stdio.h>
+#include "mhd_str.h"
+#include "mhd_assert.h"
+
+#ifndef MHD_STATICSTR_LEN_
+/**
+ * Determine length of static string / macro strings at compile time.
+ */
+#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
+#endif /* ! MHD_STATICSTR_LEN_ */
+
+
+#define TEST_STR_MAX_LEN 1024
+
+/* return zero if succeed, non-zero otherwise */
+static unsigned int
+expect_result_unquote_n (const char *const quoted, const size_t quoted_len,
+                         const char *const unquoted, const size_t unquoted_len,
+                         const unsigned int line_num)
+{
+  static char buf[TEST_STR_MAX_LEN];
+  size_t res_len;
+  unsigned int ret1;
+  unsigned int ret2;
+  unsigned int ret3;
+
+  mhd_assert (NULL != quoted);
+  mhd_assert (NULL != unquoted);
+  mhd_assert (TEST_STR_MAX_LEN > quoted_len);
+
+  /* First check: MHD_str_unquote () */
+  ret1 = 0;
+  memset (buf, '#', sizeof(buf)); /* Fill buffer with character unused in the 
check */
+  res_len = MHD_str_unquote (quoted, quoted_len, buf);
+
+  if (res_len != unquoted_len)
+  {
+    ret1 = 1;
+    fprintf (stderr,
+             "'MHD_str_unquote ()' FAILED: Wrong result size:\n");
+  }
+  else if (0 != memcmp (buf, unquoted, unquoted_len))
+  {
+    ret1 = 1;
+    fprintf (stderr,
+             "'MHD_str_unquote ()' FAILED: Wrong result string:\n");
+  }
+  if (0 != ret1)
+  {
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_unquote('%.*s', %u, ->'%.*s') -> %u\n"
+             "\tEXPECTED: MHD_str_unquote('%.*s', %u, ->'%.*s') -> %u\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) res_len, buf, (unsigned) res_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+  }
+
+  /* Second check: MHD_str_equal_quoted_bin_n () */
+  ret2 = 0;
+  if (! MHD_str_equal_quoted_bin_n (quoted, quoted_len, unquoted, 
unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_quoted_bin_n ()' FAILED: Wrong result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret2 = 1;
+  }
+
+  /* Third check: MHD_str_equal_caseless_quoted_bin_n () */
+  ret3 = 0;
+  if (! MHD_str_equal_caseless_quoted_bin_n (quoted, quoted_len, unquoted,
+                                             unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_caseless_quoted_bin_n ()' FAILED: Wrong 
result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret3 = 1;
+  }
+
+  return ret1 + ret2 + ret3;
+}
+
+
+#define expect_result_unquote(q,u) \
+    expect_result_unquote_n(q,MHD_STATICSTR_LEN_(q),\
+                            u,MHD_STATICSTR_LEN_(u),__LINE__)
+
+
+static unsigned int
+check_match (void)
+{
+  unsigned int r = 0; /**< The number of errors */
+
+  r += expect_result_unquote ("", "");
+  r += expect_result_unquote ("a", "a");
+  r += expect_result_unquote ("abc", "abc");
+  r += expect_result_unquote ("abcdef", "abcdef");
+  r += expect_result_unquote ("a\0" "bc", "a\0" "bc");
+  r += expect_result_unquote ("abc\\\"", "abc\"");
+  r += expect_result_unquote ("\\\"", "\"");
+  r += expect_result_unquote ("\\\"abc", "\"abc");
+  r += expect_result_unquote ("abc\\\\", "abc\\");
+  r += expect_result_unquote ("\\\\", "\\");
+  r += expect_result_unquote ("\\\\abc", "\\abc");
+  r += expect_result_unquote ("123\\\\\\\\\\\\\\\\", "123\\\\\\\\");
+  r += expect_result_unquote ("\\\\\\\\\\\\\\\\", "\\\\\\\\");
+  r += expect_result_unquote ("\\\\\\\\\\\\\\\\123", "\\\\\\\\123");
+  r += expect_result_unquote ("\\\\\\\"\\\\\\\"\\\\\\\"\\\\\\\"\\\\\\\"" \
+                              "\\\\\\\"\\\\\\\"\\\\\\\"\\\\\\\"\\\\\\\"", \
+                              "\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"");
+
+  return r;
+}
+
+
+/* return zero if succeed, one otherwise */
+static unsigned int
+expect_match_caseless_n (const char *const quoted, const size_t quoted_len,
+                         const char *const unquoted, const size_t unquoted_len,
+                         const unsigned int line_num)
+{
+  unsigned int ret3;
+
+  mhd_assert (NULL != quoted);
+  mhd_assert (NULL != unquoted);
+  mhd_assert (TEST_STR_MAX_LEN > quoted_len);
+
+  /* The check: MHD_str_equal_caseless_quoted_bin_n () */
+  ret3 = 0;
+  if (! MHD_str_equal_caseless_quoted_bin_n (quoted, quoted_len, unquoted,
+                                             unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_caseless_quoted_bin_n ()' FAILED: Wrong 
result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret3 = 1;
+  }
+
+  return ret3;
+}
+
+
+#define expect_match_caseless(q,u) \
+    expect_match_caseless_n(q,MHD_STATICSTR_LEN_(q),\
+                            u,MHD_STATICSTR_LEN_(u),__LINE__)
+
+static unsigned int
+check_match_caseless (void)
+{
+  unsigned int r = 0; /**< The number of errors */
+
+  r += expect_match_caseless ("a", "A");
+  r += expect_match_caseless ("abC", "aBc");
+  r += expect_match_caseless ("AbCdeF", "aBCdEF");
+  r += expect_match_caseless ("a\0" "Bc", "a\0" "bC");
+  r += expect_match_caseless ("Abc\\\"", "abC\"");
+  r += expect_match_caseless ("\\\"", "\"");
+  r += expect_match_caseless ("\\\"aBc", "\"abc");
+  r += expect_match_caseless ("abc\\\\", "ABC\\");
+  r += expect_match_caseless ("\\\\", "\\");
+  r += expect_match_caseless ("\\\\ABC", "\\abc");
+  r += expect_match_caseless ("\\\\ZYX", "\\ZYX");
+  r += expect_match_caseless ("abc", "ABC");
+  r += expect_match_caseless ("ABCabc", "abcABC");
+  r += expect_match_caseless ("abcXYZ", "ABCxyz");
+  r += expect_match_caseless ("AbCdEfABCabc", "ABcdEFabcABC");
+  r += expect_match_caseless ("a\\\\bc", "A\\BC");
+  r += expect_match_caseless ("ABCa\\\\bc", "abcA\\BC");
+  r += expect_match_caseless ("abcXYZ\\\\", "ABCxyz\\");
+  r += expect_match_caseless ("\\\\AbCdEfABCabc", "\\ABcdEFabcABC");
+
+  return r;
+}
+
+
+/* return zero if succeed, one otherwise */
+static unsigned int
+expect_result_invalid_n (const char *const quoted, const size_t quoted_len,
+                         const unsigned int line_num)
+{
+  static char buf[TEST_STR_MAX_LEN];
+  size_t res_len;
+  unsigned int ret1;
+
+  mhd_assert (NULL != quoted);
+  mhd_assert (TEST_STR_MAX_LEN > quoted_len);
+
+  /* The check: MHD_str_unquote () */
+  ret1 = 0;
+  memset (buf, '#', sizeof(buf)); /* Fill buffer with character unused in the 
check */
+  res_len = MHD_str_unquote (quoted, quoted_len, buf);
+
+  if (res_len != 0)
+  {
+    ret1 = 1;
+    fprintf (stderr,
+             "'MHD_str_unquote ()' FAILED: Wrong result size:\n");
+  }
+  if (0 != ret1)
+  {
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_unquote('%.*s', %u, (not checked)) -> %u\n"
+             "\tEXPECTED: MHD_str_unquote('%.*s', %u, (not checked)) -> 0\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (unsigned) res_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+  }
+
+  return ret1;
+}
+
+
+#define expect_result_invalid(q) \
+    expect_result_invalid_n(q,MHD_STATICSTR_LEN_(q),__LINE__)
+
+
+static unsigned int
+check_invalid (void)
+{
+  unsigned int r = 0; /**< The number of errors */
+
+  r += expect_result_invalid ("\\");
+  r += expect_result_invalid ("\\\\\\");
+  r += expect_result_invalid ("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
+  r += expect_result_invalid ("xyz\\");
+  r += expect_result_invalid ("\\\"\\");
+  r += expect_result_invalid ("\\\"\\\"\\\"\\");
+
+  return r;
+}
+
+
+/* return zero if succeed, non-zero otherwise */
+static unsigned int
+expect_result_unmatch_n (const char *const quoted, const size_t quoted_len,
+                         const char *const unquoted,
+                         const size_t unquoted_len,
+                         const unsigned int line_num)
+{
+  unsigned int ret2;
+  unsigned int ret3;
+
+  mhd_assert (NULL != quoted);
+  mhd_assert (NULL != unquoted);
+
+  /* The check: MHD_str_equal_quoted_bin_n () */
+  ret2 = 0;
+  if (MHD_str_equal_quoted_bin_n (quoted, quoted_len, unquoted, unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_quoted_bin_n ()' FAILED: Wrong result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret2 = 1;
+  }
+
+  /* The check: MHD_str_equal_quoted_bin_n () */
+  ret3 = 0;
+  if (MHD_str_equal_caseless_quoted_bin_n (quoted, quoted_len, unquoted,
+                                           unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_caseless_quoted_bin_n ()' FAILED: Wrong 
result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret3 = 1;
+  }
+
+  return ret2 + ret3;
+}
+
+
+#define expect_result_unmatch(q,u) \
+    expect_result_unmatch_n(q,MHD_STATICSTR_LEN_(q),\
+                            u,MHD_STATICSTR_LEN_(u),__LINE__)
+
+
+static unsigned int
+check_unmatch (void)
+{
+  unsigned int r = 0; /**< The number of errors */
+
+  /* Matched sequence except invalid backslash at the end */
+  r += expect_result_unmatch ("\\", "");
+  r += expect_result_unmatch ("a\\", "a");
+  r += expect_result_unmatch ("abc\\", "abc");
+  r += expect_result_unmatch ("a\0" "bc\\", "a\0" "bc");
+  r += expect_result_unmatch ("abc\\\"\\", "abc\"");
+  r += expect_result_unmatch ("\\\"\\", "\"");
+  r += expect_result_unmatch ("\\\"abc\\", "\"abc");
+  r += expect_result_unmatch ("abc\\\\\\", "abc\\");
+  r += expect_result_unmatch ("\\\\\\", "\\");
+  r += expect_result_unmatch ("\\\\abc\\", "\\abc");
+  r += expect_result_unmatch ("123\\\\\\\\\\\\\\\\\\", "123\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\\\", "\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\123\\", "\\\\\\\\123");
+  /* Invalid backslash at the end and empty string */
+  r += expect_result_unmatch ("\\", "");
+  r += expect_result_unmatch ("a\\", "");
+  r += expect_result_unmatch ("abc\\", "");
+  r += expect_result_unmatch ("a\0" "bc\\", "");
+  r += expect_result_unmatch ("abc\\\"\\", "");
+  r += expect_result_unmatch ("\\\"\\", "");
+  r += expect_result_unmatch ("\\\"abc\\", "");
+  r += expect_result_unmatch ("abc\\\\\\", "");
+  r += expect_result_unmatch ("\\\\\\", "");
+  r += expect_result_unmatch ("\\\\abc\\", "");
+  r += expect_result_unmatch ("123\\\\\\\\\\\\\\\\\\", "");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\\\", "");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\123\\", "");
+  /* Difference at binary zero */
+  r += expect_result_unmatch ("\0", "");
+  r += expect_result_unmatch ("", "\0");
+  r += expect_result_unmatch ("a\0", "a");
+  r += expect_result_unmatch ("a", "a\0");
+  r += expect_result_unmatch ("abc\0", "abc");
+  r += expect_result_unmatch ("abc", "abc\0");
+  r += expect_result_unmatch ("a\0" "bc\0", "a\0" "bc");
+  r += expect_result_unmatch ("a\0" "bc", "a\0" "bc\0");
+  r += expect_result_unmatch ("abc\\\"\0", "abc\"");
+  r += expect_result_unmatch ("abc\\\"", "abc\"\0");
+  r += expect_result_unmatch ("\\\"\0", "\"");
+  r += expect_result_unmatch ("\\\"", "\"\0");
+  r += expect_result_unmatch ("\\\"abc\0", "\"abc");
+  r += expect_result_unmatch ("\\\"abc", "\"abc\0");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\\0", "\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\", "\\\\\\\\\0");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\0" "\\\\", "\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\", "\\\\\\\0" "\\");
+  r += expect_result_unmatch ("\0" "abc", "abc");
+  r += expect_result_unmatch ("abc", "\0" "abc");
+  r += expect_result_unmatch ("\0" "abc", "0abc");
+  r += expect_result_unmatch ("0abc", "\0" "abc");
+  r += expect_result_unmatch ("xyz", "xy" "\0" "z");
+  r += expect_result_unmatch ("xy" "\0" "z", "xyz");
+  /* Difference after binary zero */
+  r += expect_result_unmatch ("abc\0" "1", "abc\0" "2");
+  r += expect_result_unmatch ("a\0" "bcx", "a\0" "bcy");
+  r += expect_result_unmatch ("\0" "abc\\\"2", "\0" "abc\"1");
+  r += expect_result_unmatch ("\0" "abc1\\\"", "\0" "abc2\"");
+  r += expect_result_unmatch ("\0" "\\\"c", "\0" "\"d");
+  r += expect_result_unmatch ("\\\"ab" "\0" "1c", "\"ab" "\0" "2c");
+  r += expect_result_unmatch ("a\0" "bcdef2", "a\0" "bcdef1");
+  r += expect_result_unmatch ("a\0" "bc2def", "a\0" "bc1def");
+  r += expect_result_unmatch ("a\0" "1bcdef", "a\0" "2bcdef");
+  r += expect_result_unmatch ("abcde\0" "f2", "abcde\0" "f1");
+  r += expect_result_unmatch ("123\\\\\\\\\\\\\0" "\\\\1", "123\\\\\\\0" 
"\\2");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\0" "1\\\\", "\\\\\\" "2\\");
+  /* One side is empty */
+  r += expect_result_unmatch ("abc", "");
+  r += expect_result_unmatch ("", "abc");
+  r += expect_result_unmatch ("1234567890", "");
+  r += expect_result_unmatch ("", "1234567890");
+  r += expect_result_unmatch ("abc\\\"", "");
+  r += expect_result_unmatch ("", "abc\"");
+  r += expect_result_unmatch ("\\\"", "");
+  r += expect_result_unmatch ("", "\"");
+  r += expect_result_unmatch ("\\\"abc", "");
+  r += expect_result_unmatch ("", "\"abc");
+  r += expect_result_unmatch ("abc\\\\", "");
+  r += expect_result_unmatch ("", "abc\\");
+  r += expect_result_unmatch ("\\\\", "");
+  r += expect_result_unmatch ("", "\\");
+  r += expect_result_unmatch ("\\\\abc", "");
+  r += expect_result_unmatch ("", "\\abc");
+  r += expect_result_unmatch ("123\\\\\\\\\\\\\\\\", "");
+  r += expect_result_unmatch ("", "123\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\", "");
+  r += expect_result_unmatch ("", "\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\123", "");
+  r += expect_result_unmatch ("", "\\\\\\\\123");
+  /* Various unmatched strings */
+  r += expect_result_unmatch ("a", "x");
+  r += expect_result_unmatch ("abc", "abcabc");
+  r += expect_result_unmatch ("abc", "abcabcabc");
+  r += expect_result_unmatch ("abc", "abcabcabcabc");
+  r += expect_result_unmatch ("ABCABC", "ABC");
+  r += expect_result_unmatch ("ABCABCABC", "ABC");
+  r += expect_result_unmatch ("ABCABCABCABC", "ABC");
+  r += expect_result_unmatch ("123\\\\\\\\\\\\\\\\\\\\", "123\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\\\\\", "\\\\\\\\");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\123\\\\", "\\\\\\\\123");
+  r += expect_result_unmatch ("\\\\\\\\\\\\\\\\", "\\\\\\\\\\");
+
+  return r;
+}
+
+
+/* return zero if succeed, one otherwise */
+static unsigned int
+expect_result_case_unmatch_n (const char *const quoted,
+                              const size_t quoted_len,
+                              const char *const unquoted,
+                              const size_t unquoted_len,
+                              const unsigned int line_num)
+{
+  unsigned int ret2;
+
+  mhd_assert (NULL != quoted);
+  mhd_assert (NULL != unquoted);
+
+  /* THe check: MHD_str_equal_quoted_bin_n () */
+  ret2 = 0;
+  if (MHD_str_equal_quoted_bin_n (quoted, quoted_len, unquoted, unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_quoted_bin_n ()' FAILED: Wrong result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret2 = 1;
+  }
+
+  return ret2;
+}
+
+
+#define expect_result_case_unmatch(q,u) \
+    expect_result_case_unmatch_n(q,MHD_STATICSTR_LEN_(q),\
+                                 u,MHD_STATICSTR_LEN_(u),__LINE__)
+
+static unsigned int
+check_unmatch_case (void)
+{
+  unsigned int r = 0; /**< The number of errors */
+
+  r += expect_result_case_unmatch ("a", "A");
+  r += expect_result_case_unmatch ("abC", "aBc");
+  r += expect_result_case_unmatch ("AbCdeF", "aBCdEF");
+  r += expect_result_case_unmatch ("a\0" "Bc", "a\0" "bC");
+  r += expect_result_case_unmatch ("Abc\\\"", "abC\"");
+  r += expect_result_case_unmatch ("\\\"aBc", "\"abc");
+  r += expect_result_case_unmatch ("abc\\\\", "ABC\\");
+  r += expect_result_case_unmatch ("\\\\ABC", "\\abc");
+  r += expect_result_case_unmatch ("\\\\ZYX", "\\ZYx");
+  r += expect_result_case_unmatch ("abc", "ABC");
+  r += expect_result_case_unmatch ("ABCabc", "abcABC");
+  r += expect_result_case_unmatch ("abcXYZ", "ABCxyz");
+  r += expect_result_case_unmatch ("AbCdEfABCabc", "ABcdEFabcABC");
+  r += expect_result_case_unmatch ("a\\\\bc", "A\\BC");
+  r += expect_result_case_unmatch ("ABCa\\\\bc", "abcA\\BC");
+  r += expect_result_case_unmatch ("abcXYZ\\\\", "ABCxyz\\");
+  r += expect_result_case_unmatch ("\\\\AbCdEfABCabc", "\\ABcdEFabcABC");
+
+  return r;
+}
+
+
+/* return zero if succeed, one otherwise */
+static unsigned int
+expect_result_caseless_unmatch_n (const char *const quoted,
+                                  const size_t quoted_len,
+                                  const char *const unquoted,
+                                  const size_t unquoted_len,
+                                  const unsigned int line_num)
+{
+  unsigned int ret2;
+  unsigned int ret3;
+
+  mhd_assert (NULL != quoted);
+  mhd_assert (NULL != unquoted);
+
+  /* The check: MHD_str_equal_quoted_bin_n () */
+  ret2 = 0;
+  if (MHD_str_equal_quoted_bin_n (quoted, quoted_len, unquoted, unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_quoted_bin_n ()' FAILED: Wrong result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret2 = 1;
+  }
+
+  /* The check: MHD_str_equal_quoted_bin_n () */
+  ret3 = 0;
+  if (MHD_str_equal_caseless_quoted_bin_n (quoted, quoted_len, unquoted,
+                                           unquoted_len))
+  {
+    fprintf (stderr,
+             "'MHD_str_equal_caseless_quoted_bin_n ()' FAILED: Wrong 
result:\n");
+    /* This does NOT print part of the string after binary zero */
+    fprintf (stderr,
+             "\tRESULT  : MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> true\n"
+             "\tEXPECTED: MHD_str_equal_caseless_quoted_bin_n('%.*s', %u, "
+             "'%.*s', %u) -> false\n",
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len,
+             (int) quoted_len, quoted, (unsigned) quoted_len,
+             (int) unquoted_len, unquoted, (unsigned) unquoted_len);
+    fprintf (stderr,
+             "The check is at line: %u\n\n", line_num);
+    ret3 = 1;
+  }
+
+  return ret2 + ret3;
+}
+
+
+#define expect_result_caseless_unmatch(q,u) \
+    expect_result_caseless_unmatch_n(q,MHD_STATICSTR_LEN_(q),\
+                                     u,MHD_STATICSTR_LEN_(u),__LINE__)
+
+
+static unsigned int
+check_unmatch_caseless (void)
+{
+  unsigned int r = 0; /**< The number of errors */
+
+  /* Matched sequence except invalid backslash at the end */
+  r += expect_result_caseless_unmatch ("a\\", "A");
+  r += expect_result_caseless_unmatch ("abC\\", "abc");
+  r += expect_result_caseless_unmatch ("a\0" "Bc\\", "a\0" "bc");
+  r += expect_result_caseless_unmatch ("abc\\\"\\", "ABC\"");
+  r += expect_result_caseless_unmatch ("\\\"\\", "\"");
+  r += expect_result_caseless_unmatch ("\\\"ABC\\", "\"abc");
+  r += expect_result_caseless_unmatch ("Abc\\\\\\", "abC\\");
+  r += expect_result_caseless_unmatch ("\\\\\\", "\\");
+  r += expect_result_caseless_unmatch ("\\\\aBc\\", "\\abC");
+  /* Difference at binary zero */
+  r += expect_result_caseless_unmatch ("a\0", "A");
+  r += expect_result_caseless_unmatch ("A", "a\0");
+  r += expect_result_caseless_unmatch ("abC\0", "abc");
+  r += expect_result_caseless_unmatch ("abc", "ABc\0");
+  r += expect_result_caseless_unmatch ("a\0" "bC\0", "a\0" "bc");
+  r += expect_result_caseless_unmatch ("a\0" "bc", "A\0" "bc\0");
+  r += expect_result_caseless_unmatch ("ABC\\\"\0", "abc\"");
+  r += expect_result_caseless_unmatch ("abc\\\"", "ABC\"\0");
+  r += expect_result_caseless_unmatch ("\\\"aBc\0", "\"abc");
+  r += expect_result_caseless_unmatch ("\\\"Abc", "\"abc\0");
+  r += expect_result_caseless_unmatch ("\\\\\\\\\\\\\\\\\0", "\\\\\\\\");
+  r += expect_result_caseless_unmatch ("\\\\\\\\\\\\\\\\", "\\\\\\\\\0");
+  r += expect_result_caseless_unmatch ("\\\\\\\\\\\\\0" "\\\\", "\\\\\\\\");
+  r += expect_result_caseless_unmatch ("\\\\\\\\\\\\\\\\", "\\\\\\\0" "\\");
+  r += expect_result_caseless_unmatch ("\0" "aBc", "abc");
+  r += expect_result_caseless_unmatch ("abc", "\0" "abC");
+  r += expect_result_caseless_unmatch ("\0" "abc", "0abc");
+  r += expect_result_caseless_unmatch ("0abc", "\0" "aBc");
+  r += expect_result_caseless_unmatch ("xyZ", "xy" "\0" "z");
+  r += expect_result_caseless_unmatch ("Xy" "\0" "z", "xyz");
+  /* Difference after binary zero */
+  r += expect_result_caseless_unmatch ("abc\0" "1", "aBC\0" "2");
+  r += expect_result_caseless_unmatch ("a\0" "bcX", "a\0" "bcy");
+  r += expect_result_caseless_unmatch ("\0" "abc\\\"2", "\0" "Abc\"1");
+  r += expect_result_caseless_unmatch ("\0" "Abc1\\\"", "\0" "abc2\"");
+  r += expect_result_caseless_unmatch ("\0" "\\\"c", "\0" "\"d");
+  r += expect_result_caseless_unmatch ("\\\"ab" "\0" "1C", "\"ab" "\0" "2C");
+  r += expect_result_caseless_unmatch ("a\0" "BCDef2", "a\0" "bcdef1");
+  r += expect_result_caseless_unmatch ("a\0" "bc2def", "a\0" "BC1def");
+  r += expect_result_caseless_unmatch ("a\0" "1bcdeF", "a\0" "2bcdef");
+  r += expect_result_caseless_unmatch ("abcde\0" "f2", "ABCDE\0" "f1");
+  r += expect_result_caseless_unmatch ("\\\"ab" "\0" "XC", "\"ab" "\0" "yC");
+  r += expect_result_caseless_unmatch ("a\0" "BCDefY", "a\0" "bcdefx");
+  r += expect_result_caseless_unmatch ("a\0" "bczdef", "a\0" "BCXdef");
+  r += expect_result_caseless_unmatch ("a\0" "YbcdeF", "a\0" "zbcdef");
+  r += expect_result_caseless_unmatch ("abcde\0" "fy", "ABCDE\0" "fX");
+
+  return r;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  unsigned int errcount = 0;
+  (void) argc; (void) argv; /* Unused. Silent compiler warning. */
+  errcount += check_match ();
+  errcount += check_match_caseless ();
+  errcount += check_invalid ();
+  errcount += check_unmatch ();
+  errcount += check_unmatch_case ();
+  errcount += check_unmatch_caseless ();
+  if (0 == errcount)
+    printf ("All tests were passed without errors.\n");
+  return errcount == 0 ? 0 : 1;
+}

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