gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] 03/04: authentication: reworked header parsing


From: gnunet
Subject: [libmicrohttpd] 03/04: authentication: reworked header parsing
Date: Tue, 31 May 2022 10:50:03 +0200

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

karlson2k pushed a commit to branch master
in repository libmicrohttpd.

commit 9039d65241daf512e7756319cd64d3d54750cb22
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Mon May 30 21:54:09 2022 +0300

    authentication: reworked header parsing
    
    Added single function to parse all enabled authentication schemes header
    strings.
    The parsing result is cached and reused thus avoiding repetitive header
    parsing.
    The new function correctly "unquotes" values (backslashes are removed)
    as required by RFC.
---
 configure.ac                              |   2 +
 src/include/microhttpd.h                  |   4 +-
 src/microhttpd/Makefile.am                |   4 +
 src/microhttpd/base64.c                   |   9 +-
 src/microhttpd/base64.h                   |  13 +-
 src/microhttpd/basicauth.c                | 113 ++--
 src/microhttpd/basicauth.h                |   9 +-
 src/microhttpd/connection.c               |   3 +
 src/microhttpd/digestauth.c               | 932 ++++++++++++++++++------------
 src/microhttpd/digestauth.h               |  42 +-
 src/microhttpd/gen_auth.c                 | 511 ++++++++++++++++
 src/microhttpd/gen_auth.h                 |  93 +++
 src/microhttpd/internal.h                 |  11 +
 src/testcurl/test_digestauth_concurrent.c |   2 +-
 w32/common/libmicrohttpd-files.vcxproj    |   2 +
 w32/common/libmicrohttpd-filters.vcxproj  |   6 +
 16 files changed, 1344 insertions(+), 412 deletions(-)

diff --git a/configure.ac b/configure.ac
index 170c9aaa..7cba50af 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2916,6 +2916,8 @@ AS_IF([[test "x$enable_dauth" != "xno"]],
 AM_CONDITIONAL([ENABLE_DAUTH], [test "x$enable_dauth" != "xno"])
 AC_MSG_RESULT([[$enable_dauth]])
 
+AM_CONDITIONAL([HAVE_ANYAUTH],[test "x$enable_bauth" != "xno" || test 
"x$enable_dauth" != "xno"])
+
 # optional: HTTP "Upgrade" support. Enabled by default
 AC_MSG_CHECKING([[whether to support HTTP "Upgrade"]])
 AC_ARG_ENABLE([[httpupgrade]],
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 84561dec..92a9278f 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
  * they are parsed as decimal numbers.
  * Example: 0x01093001 = 1.9.30-1.
  */
-#define MHD_VERSION 0x00097514
+#define MHD_VERSION 0x00097515
 
 /* If generic headers don't work on your platform, include headers
    which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -4368,6 +4368,8 @@ enum MHD_DigestAuthAlgorithm
 /**
  * The result of digest authentication of the client.
  *
+ * All error values are zero or negative.
+ *
  * @note Available since #MHD_VERSION 0x00097513
  */
 enum MHD_DigestAuthResult
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 20e29c66..cf7e7f76 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -161,6 +161,10 @@ libmicrohttpd_la_SOURCES += \
   postprocessor.c
 endif
 
+if HAVE_ANYAUTH
+libmicrohttpd_la_SOURCES += \
+  gen_auth.c gen_auth.h
+endif
 if ENABLE_DAUTH
 libmicrohttpd_la_SOURCES += \
   digestauth.c digestauth.h \
diff --git a/src/microhttpd/base64.c b/src/microhttpd/base64.c
index 1f07cd7e..3d2dd3f1 100644
--- a/src/microhttpd/base64.c
+++ b/src/microhttpd/base64.c
@@ -37,9 +37,10 @@ static const char base64_digits[] =
 
 
 char *
-BASE64Decode (const char *src)
+BASE64Decode (const char *src,
+              size_t in_len,
+              size_t *out_len)
 {
-  size_t in_len = strlen (src);
   unsigned char *dest;
   char *result;
 
@@ -52,7 +53,7 @@ BASE64Decode (const char *src)
   result = (char *) dest;
   if (NULL == result)
     return NULL; /* out of memory */
-  while (*src)
+  for (; 0 < in_len && 0 != *src; in_len -= 4)
   {
     char a = base64_digits[(unsigned char) *(src++)];
     char b = base64_digits[(unsigned char) *(src++)];
@@ -75,6 +76,8 @@ BASE64Decode (const char *src)
                 | ((unsigned char) d);
   }
   *dest = 0;
+  if (NULL != out_len)
+    *out_len = (size_t) (dest - (unsigned char *) result);
   return result;
 }
 
diff --git a/src/microhttpd/base64.h b/src/microhttpd/base64.h
index a489dc69..e5f11319 100644
--- a/src/microhttpd/base64.h
+++ b/src/microhttpd/base64.h
@@ -9,7 +9,18 @@
 #ifndef BASE64_H
 #define BASE64_H
 
+#include "mhd_options.h"
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#elif defined(HAVE_STDLIB_H)
+#include <stdlib.h>
+#else
+#include <stdio.h>
+#endif
+
 char *
-BASE64Decode (const char *src);
+BASE64Decode (const char *src,
+              size_t in_len,
+              size_t *out_len);
 
 #endif /* !BASE64_H */
diff --git a/src/microhttpd/basicauth.c b/src/microhttpd/basicauth.c
index 9ef26dca..19315d14 100644
--- a/src/microhttpd/basicauth.c
+++ b/src/microhttpd/basicauth.c
@@ -25,6 +25,7 @@
  * @author Karlson2k (Evgeny Grin)
  */
 #include "basicauth.h"
+#include "gen_auth.h"
 #include "platform.h"
 #include "mhd_limits.h"
 #include "internal.h"
@@ -32,77 +33,103 @@
 #include "mhd_compat.h"
 
 
+/**
+ * Get request's Basic Authorisation parameters.
+ * @param connection the connection to process
+ * @return pointer to request Basic Authorisation parameters structure if
+ *         request has such header (allocated in connection's pool),
+ *         NULL otherwise.
+ */
+static const struct MHD_RqBAuth *
+get_rq_bauth_params (struct MHD_Connection *connection)
+{
+  const struct MHD_AuthRqHeader *rq_params;
+
+  rq_params = MHD_get_auth_rq_params_ (connection);
+  if ( (NULL == rq_params) ||
+       (MHD_AUTHTYPE_BASIC != rq_params->auth_type) )
+    return NULL;
+
+  return rq_params->params.bauth;
+}
+
+
 /**
  * Get the username and password from the basic authorization header sent by 
the client
  *
  * @param connection The MHD connection structure
- * @param password a pointer for the password
+ * @param[out] password a pointer for the password, free using #MHD_free().
  * @return NULL if no username could be found, a pointer
- *      to the username if found
+ *      to the username if found, free using #MHD_free().
  * @ingroup authentication
  */
 _MHD_EXTERN char *
 MHD_basic_auth_get_username_password (struct MHD_Connection *connection,
                                       char **password)
 {
-  const char *header;
+  const struct MHD_RqBAuth *params;
   char *decode;
+  size_t decode_len;
   const char *separator;
-  char *user;
-
-  if ( (MHD_NO == MHD_lookup_connection_value_n (connection,
-                                                 MHD_HEADER_KIND,
-                                                 MHD_HTTP_HEADER_AUTHORIZATION,
-                                                 MHD_STATICSTR_LEN_ (
-                                                   
MHD_HTTP_HEADER_AUTHORIZATION),
-                                                 &header,
-                                                 NULL)) ||
-       (0 != strncmp (header,
-                      _MHD_AUTH_BASIC_BASE,
-                      MHD_STATICSTR_LEN_ (_MHD_AUTH_BASIC_BASE))) )
+
+  params = get_rq_bauth_params (connection);
+
+  if (NULL == params)
+    return NULL;
+
+  if ((NULL == params->token68.str) || (0 == params->token68.len))
     return NULL;
-  header += MHD_STATICSTR_LEN_ (_MHD_AUTH_BASIC_BASE);
-  if (NULL == (decode = BASE64Decode (header)))
+
+  decode = BASE64Decode (params->token68.str, params->token68.len, 
&decode_len);
+  if ((NULL == decode) || (0 == decode_len))
   {
 #ifdef HAVE_MESSAGES
     MHD_DLOG (connection->daemon,
               _ ("Error decoding basic authentication.\n"));
 #endif
+    if (NULL != decode)
+      free (decode);
     return NULL;
   }
   /* Find user:password pattern */
-  if (NULL == (separator = strchr (decode,
-                                   ':')))
+  if (NULL != (separator = memchr (decode,
+                                   ':',
+                                   decode_len)))
   {
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (connection->daemon,
-              _ ("Basic authentication doesn't contain ':' separator.\n"));
-#endif
-    free (decode);
-    return NULL;
-  }
-  if (NULL == (user = strdup (decode)))
-  {
-    free (decode);
-    return NULL;
-  }
-  user[separator - decode] = '\0'; /* cut off at ':' */
-  if (NULL != password)
-  {
-    *password = strdup (separator + 1);
-    if (NULL == *password)
+    char *user;
+    size_t user_len;
+    size_t password_len;
+
+    user = decode; /* Reuse already allocated buffer */
+    user_len = (size_t) (separator - decode);
+    user[user_len] = 0;
+
+    if (NULL == password)
+      return user;
+
+    password_len = decode_len - user_len - 1;
+    *password = (char *) malloc (password_len + 1);
+    if (NULL != *password)
     {
+      if (0 != password_len)
+        memcpy (*password, decode + user_len + 1, password_len);
+      (*password)[password_len] = 0;
+
+      return user;
+    }
 #ifdef HAVE_MESSAGES
+    else
       MHD_DLOG (connection->daemon,
-                _ ("Failed to allocate memory for password.\n"));
-#endif
-      free (decode);
-      free (user);
-      return NULL;
-    }
+                _ ("Failed to allocate memory.\n"));
+#endif /* HAVE_MESSAGES */
   }
+#ifdef HAVE_MESSAGES
+  else
+    MHD_DLOG (connection->daemon,
+              _ ("Basic authentication doesn't contain ':' separator.\n"));
+#endif
   free (decode);
-  return user;
+  return NULL;
 }
 
 
diff --git a/src/microhttpd/basicauth.h b/src/microhttpd/basicauth.h
index c3ba4a4b..c46fe27a 100644
--- a/src/microhttpd/basicauth.h
+++ b/src/microhttpd/basicauth.h
@@ -28,10 +28,17 @@
 #ifndef MHD_BASICAUTH_H
 #define MHD_BASICAUTH_H 1
 
+#include "mhd_str.h"
+
 /**
  * Beginning string for any valid Basic authentication header.
  */
-#define _MHD_AUTH_BASIC_BASE   "Basic "
+#define _MHD_AUTH_BASIC_BASE   "Basic"
+
+struct MHD_RqBAuth
+{
+  struct _MHD_cstr_w_len token68;
+};
 
 #endif /* ! MHD_BASICAUTH_H */
 
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index f178f44e..9977ea6b 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -4724,6 +4724,9 @@ connection_reset (struct MHD_Connection *connection,
     c->last = NULL;
     c->colon = NULL;
     c->header_size = 0;
+#if defined(BAUTH_SUPPORT) || defined(DAUTH_SUPPORT)
+    c->rq_auth = NULL;
+#endif
     c->keepalive = MHD_CONN_KEEPALIVE_UNKOWN;
     /* Reset the read buffer to the starting size,
        preserving the bytes we have already read. */
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 7ac5ad8b..23b41193 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -26,6 +26,7 @@
  * @author Karlson2k (Evgeny Grin)
  */
 #include "digestauth.h"
+#include "gen_auth.h"
 #include "platform.h"
 #include "mhd_limits.h"
 #include "internal.h"
@@ -158,19 +159,19 @@ enum MHD_CheckNonceNC_
   /**
    * The nonce and NC are OK (valid and NC was not used before).
    */
-  MHD_DAUTH_NONCENC_OK = MHD_DAUTH_OK,
+  MHD_CHECK_NONCENC_OK = MHD_DAUTH_OK,
 
   /**
    * The 'nonce' was overwritten with newer 'nonce' in the same slot or
    * NC was already used.
    * The validity of the 'nonce' was not be checked.
    */
-  MHD_DAUTH_NONCENC_STALE = MHD_DAUTH_NONCE_STALE,
+  MHD_CHECK_NONCENC_STALE = MHD_DAUTH_NONCE_STALE,
 
   /**
    * The 'nonce' is wrong, it was not generated before.
    */
-  MHD_DAUTH_NONCENC_WRONG = MHD_DAUTH_NONCE_WRONG,
+  MHD_CHECK_NONCENC_WRONG = MHD_DAUTH_NONCE_WRONG,
 };
 
 
@@ -536,7 +537,8 @@ digest_calc_ha1_from_user (const char *alg,
  * @param cnonce client nonce
  * @param qop qop-value: "", "auth" or "auth-int" (NOTE: only 'auth' is 
supported today.)
  * @param method method from request
- * @param uri requested URL
+ * @param uri requested URL, could be not zero-terminated
+ * @param uri_len the length of @a uri, in characters
  * @param hentity H(entity body) if qop="auth-int"
  * @param[in,out] da digest algorithm to use, also
  *        we write da->sessionkey (set to response request-digest or 
response-digest)
@@ -549,6 +551,7 @@ digest_calc_response (const char *ha1,
                       const char *qop,
                       const char *method,
                       const char *uri,
+                      size_t uri_len,
                       const char *hentity,
                       struct DigestAlgorithm *da)
 {
@@ -564,7 +567,7 @@ digest_calc_response (const char *ha1,
                  1);
   digest_update (da,
                  (const unsigned char *) uri,
-                 strlen (uri));
+                 uri_len);
 #if 0
   if (0 == strcasecmp (qop,
                        "auth-int"))
@@ -627,101 +630,17 @@ digest_calc_response (const char *ha1,
 }
 
 
-/**
- * Lookup subvalue off of the HTTP Authorization header.
- *
- * A description of the input format for 'data' is at
- * http://en.wikipedia.org/wiki/Digest_access_authentication
- *
- *
- * @param dest where to store the result (possibly truncated if
- *             the buffer is not big enough).
- * @param size size of dest
- * @param data pointer to the Authorization header
- * @param key key to look up in data
- * @return size of the located value, 0 if otherwise
- */
-static size_t
-lookup_sub_value (char *dest,
-                  size_t size,
-                  const char *data,
-                  const char *key)
+static const struct MHD_RqDAuth *
+get_rq_dauth_params (struct MHD_Connection *connection)
 {
-  size_t keylen;
-  size_t len;
-  const char *ptr;
-  const char *eq;
-  const char *q1;
-  const char *q2;
-  const char *qn;
-
-  if (0 == size)
-    return 0;
-  keylen = strlen (key);
-  ptr = data;
-  while ('\0' != *ptr)
-  {
-    if (NULL == (eq = strchr (ptr,
-                              '=')))
-      return 0;
-    q1 = eq + 1;
-    while (' ' == *q1)
-      q1++;
-    if ('\"' != *q1)
-    {
-      q2 = strchr (q1,
-                   ',');
-      qn = q2;
-    }
-    else
-    {
-      q1++;
-      q2 = strchr (q1,
-                   '\"');
-      if (NULL == q2)
-        return 0; /* end quote not found */
-      qn = q2 + 1;
-    }
-    if ( (MHD_str_equal_caseless_n_ (ptr,
-                                     key,
-                                     keylen)) &&
-         (eq == &ptr[keylen]) )
-    {
-      if (NULL == q2)
-      {
-        len = strlen (q1) + 1;
-        if (size > len)
-          size = len;
-        size--;
-        memcpy (dest,
-                q1,
-                size);
-        dest[size] = '\0';
-        return size;
-      }
-      else
-      {
-        if (size > (size_t) ((q2 - q1) + 1))
-          size = (size_t) (q2 - q1) + 1;
-        size--;
-        memcpy (dest,
-                q1,
-                size);
-        dest[size] = '\0';
-        return size;
-      }
-    }
-    if (NULL == qn)
-      return 0;
-    ptr = strchr (qn,
-                  ',');
-    if (NULL == ptr)
-      return 0;
-    ptr++;
-    while (' ' == *ptr)
-      ptr++;
-  }
-  return 0;
+  const struct MHD_AuthRqHeader *rq_params;
+
+  rq_params = MHD_get_auth_rq_params_ (connection);
+  if ( (NULL == rq_params) ||
+       (MHD_AUTHTYPE_DIGEST != rq_params->auth_type) )
+    return NULL;
+
+  return rq_params->params.dauth;
 }
 
 
@@ -738,7 +657,6 @@ get_nonce_timestamp (const char *const nonce,
                      size_t noncelen,
                      uint64_t *const ptimestamp)
 {
-  mhd_assert ((0 == noncelen) || (strlen (nonce) == noncelen));
   if (0 == noncelen)
     noncelen = strlen (nonce);
 
@@ -826,18 +744,19 @@ check_nonce_nc (struct MHD_Connection *connection,
   uint32_t mod;
   enum MHD_CheckNonceNC_ ret;
 
+  mhd_assert (0 != noncelen);
   mhd_assert (strlen (nonce) == noncelen);
   mhd_assert (0 != nc);
   if (MAX_NONCE_LENGTH < noncelen)
-    return MHD_DAUTH_NONCENC_WRONG; /* This should be impossible, but static 
analysis
+    return MHD_CHECK_NONCENC_WRONG; /* This should be impossible, but static 
analysis
                       tools have a hard time with it *and* this also
                       protects against unsafe modifications that may
                       happen in the future... */
   mod = daemon->nonce_nc_size;
   if (0 == mod)
-    return MHD_DAUTH_NONCENC_STALE;  /* no array! */
+    return MHD_CHECK_NONCENC_STALE;  /* no array! */
   if (nc >= UINT64_MAX - 64)
-    return MHD_DAUTH_NONCENC_STALE;  /* Overflow, unrealistically high value */
+    return MHD_CHECK_NONCENC_STALE;  /* Overflow, unrealistically high value */
 
   nn = &daemon->nnc[get_nonce_nc_idx (mod, nonce, noncelen)];
 
@@ -851,11 +770,11 @@ check_nonce_nc (struct MHD_Connection *connection,
     if (0 == nn->nonce[0])
     { /* The slot was never used, while the client's nonce value should be
        * recorded when it was generated by MHD */
-      ret = MHD_DAUTH_NONCENC_WRONG;
+      ret = MHD_CHECK_NONCENC_WRONG;
     }
     else if (0 != nn->nonce[noncelen])
     { /* The value is the slot is wrong */
-      ret =  MHD_DAUTH_NONCENC_STALE;
+      ret =  MHD_CHECK_NONCENC_STALE;
     }
     else
     {
@@ -863,7 +782,7 @@ check_nonce_nc (struct MHD_Connection *connection,
       if (! get_nonce_timestamp (nn->nonce, 0, &slot_ts))
       {
         mhd_assert (0); /* The value is the slot is wrong */
-        ret = MHD_DAUTH_NONCENC_STALE;
+        ret = MHD_CHECK_NONCENC_STALE;
       }
       else
       {
@@ -873,21 +792,21 @@ check_nonce_nc (struct MHD_Connection *connection,
         {
           /* The nonce from the client may not have been placed in the slot
            * because another nonce in that slot has not yet expired. */
-          ret = MHD_DAUTH_NONCENC_STALE;
+          ret = MHD_CHECK_NONCENC_STALE;
         }
         else if (TRIM_TO_TIMESTAMP (UINT64_MAX) / 2 >= ts_diff)
         {
           /* Too large value means that nonce_time is less than slot_ts.
            * The nonce from the client may have been overwritten by the newer
            * nonce. */
-          ret = MHD_DAUTH_NONCENC_STALE;
+          ret = MHD_CHECK_NONCENC_STALE;
         }
         else
         {
           /* The nonce from the client should be generated after the nonce
            * in the slot has been expired, the nonce must be recorded, but
            * it's not. */
-          ret = MHD_DAUTH_NONCENC_WRONG;
+          ret = MHD_CHECK_NONCENC_WRONG;
         }
       }
     }
@@ -908,7 +827,7 @@ check_nonce_nc (struct MHD_Connection *connection,
     else
       nn->nmask = 0;                /* big jump, unset all bits in the mask */
     nn->nc = nc;
-    ret = MHD_DAUTH_NONCENC_OK;
+    ret = MHD_CHECK_NONCENC_OK;
   }
   else if (nc < nn->nc)
   {
@@ -919,15 +838,15 @@ check_nonce_nc (struct MHD_Connection *connection,
     {
       /* Out-of-order nonce, but within 64-bit bitmask, set bit */
       nn->nmask |= (UINT64_C (1) << (nn->nc - nc - 1));
-      ret = MHD_DAUTH_NONCENC_OK;
+      ret = MHD_CHECK_NONCENC_OK;
     }
     else
       /* 'nc' was already used or too old (more then 64 values ago) */
-      ret = MHD_DAUTH_NONCENC_STALE;
+      ret = MHD_CHECK_NONCENC_STALE;
   }
   else /* if (nc == nn->nc) */
     /* 'nc' was already used */
-    ret = MHD_DAUTH_NONCENC_STALE;
+    ret = MHD_CHECK_NONCENC_STALE;
 
   MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
 
@@ -947,28 +866,40 @@ check_nonce_nc (struct MHD_Connection *connection,
 _MHD_EXTERN char *
 MHD_digest_auth_get_username (struct MHD_Connection *connection)
 {
-  char user[MAX_USERNAME_LENGTH];
-  const char *header;
-
-  if (MHD_NO == MHD_lookup_connection_value_n (connection,
-                                               MHD_HEADER_KIND,
-                                               MHD_HTTP_HEADER_AUTHORIZATION,
-                                               MHD_STATICSTR_LEN_ (
-                                                 
MHD_HTTP_HEADER_AUTHORIZATION),
-                                               &header,
-                                               NULL))
+  const struct MHD_RqDAuth *params;
+  char *username;
+  size_t username_len;
+
+  params = get_rq_dauth_params (connection);
+  if (NULL == params)
     return NULL;
-  if (0 != strncmp (header,
-                    _MHD_AUTH_DIGEST_BASE,
-                    MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE)))
+
+  if (NULL == params->username.value.str)
     return NULL;
-  header += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE);
-  if (0 == lookup_sub_value (user,
-                             sizeof (user),
-                             header,
-                             "username"))
+
+  username_len = params->username.value.len;
+  username = malloc (username_len + 1);
+  if (NULL == username)
     return NULL;
-  return strdup (user);
+
+  if (! params->username.quoted)
+  {
+    /* The username is not quoted, no need to unquote */
+    if (0 != username_len)
+      memcpy (username, params->username.value.str, username_len);
+    username[username_len] = 0; /* Zero-terminate */
+  }
+  else
+  {
+    /* Need to properly unquote the username */
+    mhd_assert (0 != username_len); /* Quoted string may not be zero-legth */
+    username_len = MHD_str_unquote (params->username.value.str, username_len,
+                                    username);
+    mhd_assert (0 != username_len); /* The unquoted string cannot be empty */
+    username[username_len] = 0; /* Zero-terminate */
+  }
+
+  return username;
 }
 
 
@@ -1346,6 +1277,91 @@ check_argument_match (struct MHD_Connection *connection,
 }
 
 
+/**
+ * The size of the unquoting buffer in stack
+ */
+#define _MHD_STATIC_UNQ_BUFFER_SIZE 128
+
+/**
+ * The result of parameter unquoting
+ */
+enum _MHD_GetUnqResult
+{
+  _MHD_UNQ_NON_EMPTY = 0,                      /**< The sting is not empty */
+  _MHD_UNQ_NO_STRING = MHD_DAUTH_WRONG_HEADER, /**< No string (no such 
parameter) */
+  _MHD_UNQ_EMPTY = 1,                          /**< The string is empty */
+  _MHD_UNQ_TOO_LARGE = 2,                      /**< The string is too large to 
unqoute */
+  _MHD_UNQ_OUT_OF_MEM = 3                      /**< Out of memory error */
+};
+
+
+/**
+ * Get Digest authorisation parameter as unquoted string.
+ * @param param the parameter to process
+ * @param tmp1 the small buffer in stack
+ * @param ptmp2 the pointer to pointer to malloc'ed buffer
+ * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
+ * @param[out] unquoted the pointer to store the result, NOT zero terminated
+ * @return enum code indicating result of the process
+ */
+static enum _MHD_GetUnqResult
+get_unqouted_param (const struct MHD_RqDAuthParam *param,
+                    char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
+                    char **ptmp2,
+                    size_t *ptmp2_size,
+                    struct _MHD_cstr_w_len *unquoted)
+{
+  char *str;
+  size_t len;
+  mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
+  mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
+  mhd_assert ((0 == *ptmp2_size) || \
+              (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
+
+  if (NULL == param->value.str)
+  {
+    const struct _MHD_cstr_w_len res = {NULL, 0};
+    mhd_assert (! param->quoted);
+    mhd_assert (0 == param->value.len);
+    memcpy (unquoted, &res, sizeof(res));
+    return _MHD_UNQ_NO_STRING;
+  }
+  if (! param->quoted)
+  {
+    memcpy (unquoted, &param->value, sizeof(param->value));
+    return (0 == param->value.len) ? _MHD_UNQ_EMPTY : _MHD_UNQ_NON_EMPTY;
+  }
+  /* The value is present and is quoted, needs to be copied and unquoted */
+  mhd_assert (0 != param->value.len);
+  if (param->value.len <= _MHD_STATIC_UNQ_BUFFER_SIZE)
+    str = tmp1;
+  else if (param->value.len <= *ptmp2_size)
+    str = *ptmp2;
+  else
+  {
+    if (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
+      return _MHD_UNQ_TOO_LARGE;
+    if (NULL != *ptmp2)
+      free (*ptmp2);
+    *ptmp2 = (char *) malloc (param->value.len);
+    if (NULL == *ptmp2)
+      return _MHD_UNQ_OUT_OF_MEM;
+    *ptmp2_size = param->value.len;
+    str = *ptmp2;
+  }
+
+  len = MHD_str_unquote (param->value.str, param->value.len, str);
+  if (1)
+  {
+    const struct _MHD_cstr_w_len res = {str, len};
+    memcpy (unquoted, &res, sizeof(res));
+  }
+  mhd_assert (0 != unquoted->len);
+  mhd_assert (unquoted->len < param->value.len);
+  return _MHD_UNQ_NON_EMPTY;
+}
+
+
 /**
  * Authenticates the authorization header sent by the client
  *
@@ -1375,10 +1391,6 @@ digest_auth_check_all (struct MHD_Connection *connection,
                        unsigned int nonce_timeout)
 {
   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
-  size_t len;
-  const char *header;
-  char nonce[MAX_NONCE_LENGTH];
-  size_t nonce_len;
   char cnonce[MAX_NONCE_LENGTH];
   const unsigned int digest_size = digest_get_size (da);
   char ha1[VLA_ARRAY_LEN_DIGEST (digest_size) * 2 + 1];
@@ -1389,219 +1401,368 @@ digest_auth_check_all (struct MHD_Connection 
*connection,
   char noncehashexp[NONCE_STD_LEN (VLA_ARRAY_LEN_DIGEST (digest_size)) + 1];
   uint64_t nonce_time;
   uint64_t t;
-  size_t left; /* number of characters left in 'header' for 'uri' */
   uint64_t nci;
   char *qmark;
+  const struct MHD_RqDAuth *params;
+  char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE]; /**< Temporal buffer in stack for 
unqouting */
+  char *tmp2;     /**< Temporal malloc'ed buffer for unqouting */
+  size_t tmp2_size; /**< The size of @a tmp2 buffer */
+  struct _MHD_cstr_w_len unquoted;
+  enum _MHD_GetUnqResult unq_res;
+  enum MHD_DigestAuthResult ret;
+#ifdef HAVE_MESSAGES
+  bool err_logged;
+#endif /* HAVE_MESSAGES */
 
-  VLA_CHECK_LEN_DIGEST (digest_size);
-  if (MHD_NO == MHD_lookup_connection_value_n (connection,
-                                               MHD_HEADER_KIND,
-                                               MHD_HTTP_HEADER_AUTHORIZATION,
-                                               MHD_STATICSTR_LEN_ (
-                                                 
MHD_HTTP_HEADER_AUTHORIZATION),
-                                               &header,
-                                               NULL))
-    return MHD_DAUTH_WRONG_HEADER;
-  if (0 != strncmp (header,
-                    _MHD_AUTH_DIGEST_BASE,
-                    MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE)))
-    return MHD_DAUTH_WRONG_HEADER;
-  header += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE);
-  left = strlen (header);
-
-  if (1)
-  {
-    char un[MAX_USERNAME_LENGTH];
-
-    len = lookup_sub_value (un,
-                            sizeof (un),
-                            header,
-                            "username");
-    if (0 == len)
-      return MHD_DAUTH_WRONG_HEADER;
-    if (0 != strcmp (username,
-                     un))
-      return MHD_DAUTH_WRONG_USERNAME;
-    left -= strlen ("username") + len;
-  }
-
-  if (1)
-  {
-    char r[MAX_REALM_LENGTH];
-
-    len = lookup_sub_value (r,
-                            sizeof (r),
-                            header,
-                            "realm");
-    if (0 == len)
-      return MHD_DAUTH_WRONG_HEADER;
-    if (0 != strcmp (realm,
-                     r))
-      return MHD_DAUTH_WRONG_REALM;
-    left -= strlen ("realm") + len;
-  }
-
-  if (0 == (len = lookup_sub_value (nonce,
-                                    sizeof (nonce),
-                                    header,
-                                    "nonce")))
-    return MHD_DAUTH_WRONG_HEADER;
-  nonce_len = len;
-  left -= strlen ("nonce") + len;
-  if (left > 32 * 1024)
-  {
-    /* we do not permit URIs longer than 32k, as we want to
-       make sure to not blow our stack (or per-connection
-       heap memory limit).  Besides, 32k is already insanely
-       large, but of course in theory the
-       #MHD_OPTION_CONNECTION_MEMORY_LIMIT might be very large
-       and would thus permit sending a >32k authorization
-       header value. */
-    return MHD_DAUTH_WRONG_HEADER;
-  }
-  if (! get_nonce_timestamp (nonce, nonce_len, &nonce_time))
-  {
+  tmp2 = NULL;
+  tmp2_size = 0;
 #ifdef HAVE_MESSAGES
-    MHD_DLOG (daemon,
-              _ ("Authentication failed, invalid timestamp format.\n"));
-#endif
+  err_logged = false;
+#endif /* HAVE_MESSAGES */
+
+  params = get_rq_dauth_params (connection);
+  if (NULL == params)
     return MHD_DAUTH_WRONG_HEADER;
-  }
 
-  t = MHD_monotonic_msec_counter ();
-  /*
-   * First level vetting for the nonce validity: if the timestamp
-   * attached to the nonce exceeds `nonce_timeout', then the nonce is
-   * invalid.
-   */
-  if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
+  do /* Only to avoid "goto" */
   {
-    /* too old */
-    return MHD_DAUTH_NONCE_STALE;
-  }
+    /* Check 'username' */
+    unq_res = get_unqouted_param (&params->username, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      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;
+      }
+      break;
+    }
+    /* 'unquoted" may not contain binary zero */
+    if ( (0 != strncmp (username, unquoted.str, unquoted.len)) ||
+         (0 != username[unquoted.len]) )
+    {
+      ret = MHD_DAUTH_WRONG_USERNAME;
+      break;
+    }
+    /* 'username' valid */
 
-  calculate_nonce (nonce_time,
-                   connection->method,
-                   daemon->digest_auth_random,
-                   daemon->digest_auth_rand_size,
-                   connection->url,
-                   realm,
-                   da,
-                   noncehashexp);
-  /*
-   * Second level vetting for the nonce validity
-   * if the timestamp attached to the nonce is valid
-   * and possibly fabricated (in case of an attack)
-   * the attacker must also know the random seed to be
-   * able to generate a "sane" nonce, which if he does
-   * not, the nonce fabrication process going to be
-   * very hard to achieve.
-   */
-  if (0 != strcmp (nonce,
-                   noncehashexp))
-  {
-    return MHD_DAUTH_NONCE_WRONG;
-  }
-  if ( (0 == lookup_sub_value (cnonce,
-                               sizeof (cnonce),
-                               header,
-                               "cnonce")) ||
-       (0 == lookup_sub_value (qop,
-                               sizeof (qop),
-                               header,
-                               "qop")) ||
-       ( (0 != strcmp (qop,
-                       "auth")) &&
-         (0 != strcmp (qop,
-                       "")) ) ||
-       (0 == (len = lookup_sub_value (nc,
-                                      sizeof (nc),
-                                      header,
-                                      "nc")) ) ||
-       (0 == lookup_sub_value (response,
-                               sizeof (response),
-                               header,
-                               "response")) )
-  {
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (daemon,
-              _ ("Authentication failed, invalid format.\n"));
-#endif
-    return MHD_DAUTH_WRONG_HEADER;
-  }
-  if (len != MHD_strx_to_uint64_n_ (nc,
-                                    len,
-                                    &nci))
-  {
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (daemon,
-              _ ("Authentication failed, invalid nc format.\n"));
-#endif
-    return MHD_DAUTH_WRONG_HEADER;   /* invalid nonce format */
-  }
-  if (0 == nci)
-  {
+    /* Check 'realm' */
+    unq_res = get_unqouted_param (&params->realm, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      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;
+      }
+      break;
+    }
+    /* 'unquoted" may not contain binary zero */
+    if ( (0 != strncmp (realm, unquoted.str, unquoted.len)) ||
+         (0 != realm[unquoted.len]) )
+    {
+      ret = MHD_DAUTH_WRONG_REALM;
+      break;
+    }
+    /* 'realm' valid */
+
+    /* Check 'nonce' */
+    unq_res = get_unqouted_param (&params->nonce, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      if (_MHD_UNQ_NO_STRING == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      else if (_MHD_UNQ_EMPTY == unq_res)
+        ret = MHD_DAUTH_NONCE_WRONG;
+      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;
+      }
+      break;
+    }
+    /* TODO: check correct 'nonce' length */
+    if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time))
+    {
 #ifdef HAVE_MESSAGES
-    MHD_DLOG (daemon,
-              _ ("Authentication failed, invalid 'nc' value.\n"));
+      MHD_DLOG (daemon,
+                _ ("Authentication failed, invalid timestamp format.\n"));
+      err_logged = true;
 #endif
-    return MHD_DAUTH_WRONG_HEADER;   /* invalid nc value */
-  }
+      ret = MHD_DAUTH_NONCE_WRONG;
+      break;
+    }
+    t = MHD_monotonic_msec_counter ();
+    /*
+     * First level vetting for the nonce validity: if the timestamp
+     * attached to the nonce exceeds `nonce_timeout', then the nonce is
+     * invalid.
+     */
+    if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
+    {
+      /* too old */
+      ret = MHD_DAUTH_NONCE_STALE;
+      break;
+    }
 
-  if (1)
-  {
-    enum MHD_CheckNonceNC_ nonce_nc_check;
+    calculate_nonce (nonce_time,
+                     connection->method,
+                     daemon->digest_auth_random,
+                     daemon->digest_auth_rand_size,
+                     connection->url,
+                     realm,
+                     da,
+                     noncehashexp);
     /*
-     * Checking if that combination of nonce and nc is sound
-     * and not a replay attack attempt. Refuse if nonce was not
-     * generated previously.
+     * Second level vetting for the nonce validity
+     * if the timestamp attached to the nonce is valid
+     * and possibly fabricated (in case of an attack)
+     * the attacker must also know the random seed to be
+     * able to generate a "sane" nonce, which if he does
+     * not, the nonce fabrication process going to be
+     * very hard to achieve.
      */
-    nonce_nc_check = check_nonce_nc (connection,
-                                     nonce,
-                                     nonce_len,
-                                     nonce_time,
-                                     nci);
-    if (MHD_DAUTH_NONCENC_STALE == nonce_nc_check)
+    if ((0 != strncmp (noncehashexp, unquoted.str, unquoted.len)) ||
+        (0 != noncehashexp[unquoted.len]))
+    {
+      ret = MHD_DAUTH_NONCE_WRONG;
+      break;
+    }
+    /* 'nonce' valid */
+
+    /* Get 'cnonce' */
+    unq_res = get_unqouted_param (&params->cnonce, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      if (_MHD_UNQ_NO_STRING == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      else if (_MHD_UNQ_EMPTY == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      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;
+      }
+      break;
+    }
+    if (sizeof(cnonce) <= unquoted.len)
+    {
+      /* TODO: handle large client nonces */
+      ret = MHD_DAUTH_ERROR;
+      break;
+    }
+    /* TODO: avoid memcpy() */
+    memcpy (cnonce, unquoted.str, unquoted.len);
+    cnonce[unquoted.len] = 0;
+    /* Got 'cnonce' */
+
+    /* Get 'qop' */
+    unq_res = get_unqouted_param (&params->qop, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      if (_MHD_UNQ_NO_STRING == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      else if (_MHD_UNQ_EMPTY == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      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;
+      }
+      break;
+    }
+    if (sizeof(qop) <= unquoted.len)
+    {
+      /* TODO: handle large client qop */
+      ret = MHD_DAUTH_ERROR;
+      break;
+    }
+    /* TODO: avoid memcpy() */
+    memcpy (qop, unquoted.str, unquoted.len);
+    qop[unquoted.len] = 0;
+    /* TODO: use caseless match, use dedicated return code */
+    if ( (0 != strcmp (qop, "auth")) &&
+         (0 != strcmp (qop,"")) )
+    {
+      ret = MHD_DAUTH_WRONG_HEADER;
+      break;
+    }
+    /* Got 'qop' */
+
+    /* Get 'nc' */
+    unq_res = get_unqouted_param (&params->nc, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      if (_MHD_UNQ_NO_STRING == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      else if (_MHD_UNQ_EMPTY == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      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;
+      }
+      break;
+    }
+    if (sizeof(nc) <= unquoted.len)
+    {
+      /* TODO: handle large client nc */
+      ret = MHD_DAUTH_ERROR;
+      break;
+    }
+    /* TODO: avoid memcpy() */
+    memcpy (nc, unquoted.str, unquoted.len);
+    nc[unquoted.len] = 0;
+    if (unquoted.len != MHD_strx_to_uint64_n_ (nc,
+                                               unquoted.len,
+                                               &nci))
     {
 #ifdef HAVE_MESSAGES
       MHD_DLOG (daemon,
-                _ ("Stale nonce received. If this happens a lot, you should "
-                   "probably increase the size of the nonce array.\n"));
+                _ ("Authentication failed, invalid nc format.\n"));
+      err_logged = true;
 #endif
-      return MHD_DAUTH_NONCE_STALE;
+      ret = MHD_DAUTH_WRONG_HEADER;   /* invalid nonce format */
+      break;
     }
-    else if (MHD_DAUTH_NONCENC_WRONG == nonce_nc_check)
+    if (0 == nci)
     {
 #ifdef HAVE_MESSAGES
       MHD_DLOG (daemon,
-                _ ("Received nonce that technically valid, but was not "
-                   "generated by MHD. This may indicate an attack 
attempt.\n"));
+                _ ("Authentication failed, invalid 'nc' value.\n"));
+      err_logged = true;
 #endif
-      return MHD_DAUTH_NONCE_WRONG;
+      ret = MHD_DAUTH_WRONG_HEADER;   /* invalid nc value */
+      break;
     }
-    mhd_assert (MHD_DAUTH_NONCENC_OK == nonce_nc_check);
-  }
+    /* Got 'nc' */
 
-  if (1)
-  {
-    char *uri;
+    /* Get 'response' */
+    unq_res = get_unqouted_param (&params->response, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
+    {
+      if (_MHD_UNQ_NO_STRING == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      else if (_MHD_UNQ_EMPTY == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      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;
+      }
+      break;
+    }
+    if (sizeof(response) <= unquoted.len)
+    {
+      /* TODO: handle large client response */
+      ret = MHD_DAUTH_ERROR;
+      break;
+    }
+    /* TODO: avoid memcpy() */
+    memcpy (response, unquoted.str, unquoted.len);
+    response[unquoted.len] = 0;
+    /* Got 'response' */
 
-    uri = malloc (left + 1);
-    if (NULL == uri)
+    if (1)
     {
+      enum MHD_CheckNonceNC_ nonce_nc_check;
+      /*
+       * Checking if that combination of nonce and nc is sound
+       * and not a replay attack attempt. Refuse if nonce was not
+       * generated previously.
+       */
+      nonce_nc_check = check_nonce_nc (connection,
+                                       noncehashexp,
+                                       NONCE_STD_LEN (digest_size),
+                                       nonce_time,
+                                       nci);
+      if (MHD_CHECK_NONCENC_STALE == nonce_nc_check)
+      {
 #ifdef HAVE_MESSAGES
-      MHD_DLOG (daemon,
-                _ ("Failed to allocate memory for auth header processing.\n"));
-#endif /* HAVE_MESSAGES */
-      return MHD_DAUTH_ERROR;
+        MHD_DLOG (daemon,
+                  _ ("Stale nonce received. If this happens a lot, you should "
+                     "probably increase the size of the nonce array.\n"));
+        err_logged = true;
+#endif
+        ret = MHD_DAUTH_NONCE_STALE;
+        break;
+      }
+      else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
+      {
+#ifdef HAVE_MESSAGES
+        MHD_DLOG (daemon,
+                  _ ("Received nonce that technically valid, but was not "
+                     "generated by MHD. This may indicate an attack 
attempt.\n"));
+        err_logged = true;
+#endif
+        ret = MHD_DAUTH_NONCE_WRONG;
+        break;
+      }
+      mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
     }
-    if (0 == lookup_sub_value (uri,
-                               left + 1,
-                               header,
-                               "uri"))
+
+    /* Get 'uri' */
+    unq_res = get_unqouted_param (&params->uri, tmp1, &tmp2, &tmp2_size,
+                                  &unquoted);
+    if (_MHD_UNQ_NON_EMPTY != unq_res)
     {
-      free (uri);
-      return MHD_DAUTH_WRONG_HEADER;
+      if (_MHD_UNQ_NO_STRING == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      else if (_MHD_UNQ_EMPTY == unq_res)
+        ret = MHD_DAUTH_WRONG_HEADER;
+      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;
+      }
+      break;
     }
     if (NULL != digest)
     {
@@ -1609,7 +1770,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
       digest_calc_ha1_from_digest (digest_get_algo_name (da),
                                    da,
                                    digest,
-                                   nonce,
+                                   noncehashexp,
                                    cnonce);
     }
     else
@@ -1620,7 +1781,7 @@ digest_auth_check_all (struct MHD_Connection *connection,
                                  username,
                                  realm,
                                  password,
-                                 nonce,
+                                 noncehashexp,
                                  cnonce,
                                  da);
     }
@@ -1629,60 +1790,111 @@ digest_auth_check_all (struct MHD_Connection 
*connection,
             digest_size * 2 + 1);
     /* This will initialize da->sessionkey (respexp) */
     digest_calc_response (ha1,
-                          nonce,
+                          noncehashexp,
                           nc,
                           cnonce,
                           qop,
                           connection->method,
-                          uri,
+                          unquoted.str,
+                          unquoted.len,
                           hentity,
                           da);
-    qmark = strchr (uri,
-                    '?');
-    if (NULL != qmark)
-      *qmark = '\0';
-
-    /* Need to unescape URI before comparing with connection->url */
-    daemon->unescape_callback (daemon->unescape_callback_cls,
-                               connection,
-                               uri);
-    if (0 != strcmp (uri,
-                     connection->url))
-    {
-#ifdef HAVE_MESSAGES
-      MHD_DLOG (daemon,
-                _ ("Authentication failed, URI does not match.\n"));
-#endif
-      free (uri);
-      return MHD_DAUTH_WRONG_URI;
-    }
-
     if (1)
     {
-      const char *args = qmark;
-
-      if (NULL == args)
-        args = "";
+      char *uri;
+      size_t uri_len;
+      uri_len = unquoted.len;
+      /* TODO: simplify string copy, avoid potential double copy */
+      if ( ((tmp1 != unquoted.str) && (tmp2 != unquoted.str)) ||
+           ((tmp1 == unquoted.str) && (sizeof(tmp1) >= unquoted.len)) ||
+           ((tmp2 == unquoted.str) && (tmp2_size >= unquoted.len)))
+      {
+        char *buf;
+        mhd_assert ((tmp1 != unquoted.str) || \
+                    (sizeof(tmp1) == unquoted.len));
+        mhd_assert ((tmp2 != unquoted.str) || \
+                    (tmp2_size == unquoted.len));
+        buf = malloc (unquoted.len + 1);
+        if (NULL == buf)
+        {
+          ret = MHD_DAUTH_ERROR;
+          break;
+        }
+        memcpy (buf, unquoted.str, unquoted.len);
+        if (NULL != tmp2)
+          free (tmp2);
+        tmp2 = buf;
+        tmp2_size = unquoted.len + 1;
+        uri = tmp2;
+      }
+      else if (tmp1 == unquoted.str)
+        uri = tmp1;
       else
-        args++;
-      if (MHD_NO ==
-          check_argument_match (connection,
-                                args) )
+      {
+        mhd_assert (tmp2 == unquoted.str);
+        uri = tmp2;
+      }
+
+      uri[uri_len] = 0;
+      qmark = memchr (uri,
+                      '?',
+                      uri_len);
+      if (NULL != qmark)
+        *qmark = '\0';
+
+      /* Need to unescape URI before comparing with connection->url */
+      daemon->unescape_callback (daemon->unescape_callback_cls,
+                                 connection,
+                                 uri);
+      if (0 != strcmp (uri,
+                       connection->url))
       {
 #ifdef HAVE_MESSAGES
         MHD_DLOG (daemon,
-                  _ ("Authentication failed, arguments do not match.\n"));
+                  _ ("Authentication failed, URI does not match.\n"));
+        err_logged = true;
 #endif
-        free (uri);
-        return MHD_DAUTH_WRONG_URI;
+        ret = MHD_DAUTH_WRONG_URI;
+        break;
       }
+
+      if (1)
+      {
+        const char *args = qmark;
+
+        if (NULL == args)
+          args = "";
+        else
+          args++;
+        if (MHD_NO ==
+            check_argument_match (connection,
+                                  args) )
+        {
+#ifdef HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    _ ("Authentication failed, arguments do not match.\n"));
+          err_logged = true;
+#endif
+          ret = MHD_DAUTH_WRONG_URI;
+          break;
+        }
+      }
+
+      ret = (0 == strcmp (response,
+                          digest_get_hex_buffer (da)))
+      ? MHD_DAUTH_OK
+      : MHD_DAUTH_RESPONSE_WRONG;
     }
-    free (uri);
+  } while (0);
+  if (NULL != tmp2)
+    free (tmp2);
+
+  if ((MHD_DAUTH_OK != ret) && ! err_logged)
+  {
+    (void) 0; /* TODO: add logging */
   }
-  return (0 == strcmp (response,
-                       digest_get_hex_buffer (da)))
-         ? MHD_DAUTH_OK
-         : MHD_DAUTH_RESPONSE_WRONG;
+
+  return ret;
 }
 
 
diff --git a/src/microhttpd/digestauth.h b/src/microhttpd/digestauth.h
index 689c0487..77c7c402 100644
--- a/src/microhttpd/digestauth.h
+++ b/src/microhttpd/digestauth.h
@@ -28,10 +28,48 @@
 
 #ifndef MHD_DIGESTAUTH_H
 #define MHD_DIGESTAUTH_H 1
+
+#include "mhd_options.h"
+#include "mhd_str.h"
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif /* HAVE_STDBOOL_H */
+
+
+/**
+ * The maximum supported size for Digest Auth parameters, like "real",
+ * "username" etc. This limitation is used only for quoted parameters.
+ * Parameters without quoted backslash character will be processed as long
+ * as they fit connection pool (buffer) size.
+ */
+#define _MHD_AUTH_DIGEST_MAX_PARAM_SIZE (65535)
+
 /**
- * Beginning string for any valid Digest authentication header.
+ * Beginning string for any valid Digest Authentication header.
  */
-#define _MHD_AUTH_DIGEST_BASE   "Digest "
+#define _MHD_AUTH_DIGEST_BASE   "Digest"
+
+struct MHD_RqDAuthParam
+{
+  struct _MHD_cstr_w_len value;
+  bool quoted;
+};
+
+struct MHD_RqDAuth
+{
+  struct MHD_RqDAuthParam nonce;
+  struct MHD_RqDAuthParam opaque;
+  struct MHD_RqDAuthParam algorithm;
+  struct MHD_RqDAuthParam response;
+  struct MHD_RqDAuthParam username;
+  struct MHD_RqDAuthParam username_ext;
+  struct MHD_RqDAuthParam realm;
+  struct MHD_RqDAuthParam uri;
+  struct MHD_RqDAuthParam qop;
+  struct MHD_RqDAuthParam cnonce;
+  struct MHD_RqDAuthParam nc;
+  bool userhash;
+};
 
 #endif /* ! MHD_DIGESTAUTH_H */
 
diff --git a/src/microhttpd/gen_auth.c b/src/microhttpd/gen_auth.c
new file mode 100644
index 00000000..e993fb20
--- /dev/null
+++ b/src/microhttpd/gen_auth.c
@@ -0,0 +1,511 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library.
+  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/gen_auth.c
+ * @brief  HTTP authorisation general functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "gen_auth.h"
+#include "internal.h"
+#include "connection.h"
+#include "mhd_str.h"
+#include "mhd_assert.h"
+
+#ifdef BAUTH_SUPPORT
+#include "basicauth.h"
+#endif /* BAUTH_SUPPORT */
+#ifdef DAUTH_SUPPORT
+#include "digestauth.h"
+#endif /* DAUTH_SUPPORT */
+
+#if ! defined(BAUTH_SUPPORT) && ! defined(DAUTH_SUPPORT)
+#error This file requires Basic or Digest authentication support
+#endif
+
+#ifdef BAUTH_SUPPORT
+/**
+ * Parse request Authorization header parameters for Basic Authentication
+ * @param str the header string, everything after "Basic " substring
+ * @param str_len the length of @a str in characters
+ * @param[out] pbauth the pointer to the structure with Basic Authentication
+ *               parameters
+ * @return true if parameters has been successfully parsed,
+ *         false if format of the @a str is invalid
+ */
+static bool
+parse_bauth_params (const char *str,
+                    size_t str_len,
+                    struct MHD_RqBAuth *pbauth)
+{
+  size_t i;
+
+  i = 0;
+
+  /* Skip all whitespaces at start */
+  while (i < str_len && (' ' == str[i] || '\t' == str[i]))
+    i++;
+
+  if (str_len > i)
+  {
+    size_t token68_start;
+    size_t token68_len;
+
+    /* 'i' points to the first non-whitespace char after scheme token */
+    token68_start = i;
+    /* Find end of the token. Token cannot contain whitespace. */
+    while (i < str_len && ' ' != str[i] && '\t' != str[i])
+    {
+      if (0 == str[0])
+        return false; /* Binary zero is not allowed */
+      i++;
+    }
+    token68_len = i - token68_start;
+    mhd_assert (0 != token68_len);
+
+    /* Skip all whitespaces */
+    while (i < str_len && (' ' == str[i] || '\t' == str[i]))
+      i++;
+    /* Check whether any garbage is present at the end of the string */
+    if (str_len != i)
+      return false;
+    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));
+    }
+  }
+  return true;
+}
+
+
+#endif /* BAUTH_SUPPORT */
+
+#ifdef DAUTH_SUPPORT
+
+/**
+ * Helper structure to map token name to position where to put token's value
+ */
+struct dauth_token_param
+{
+  const struct _MHD_cstr_w_len *const tk_name;
+  struct MHD_RqDAuthParam *const param;
+};
+
+/**
+ * Parse request Authorization header parameters for Digest Authentication
+ * @param str the header string, everything after "Digest " substring
+ * @param str_len the length of @a str in characters
+ * @param[out] pdauth the pointer to the structure with Digest Authentication
+ *               parameters
+ * @return true if parameters has been successfully parsed,
+ *         false if format of the @a str is invalid
+ */
+static bool
+parse_dauth_params (const char *str,
+                    const size_t str_len,
+                    struct MHD_RqDAuth *pdauth)
+{
+  static const struct _MHD_cstr_w_len nonce_tk = _MHD_S_STR_W_LEN ("nonce");
+  static const struct _MHD_cstr_w_len opaque_tk = _MHD_S_STR_W_LEN ("opaque");
+  static const struct _MHD_cstr_w_len algorithm_tk =
+    _MHD_S_STR_W_LEN ("algorithm");
+  static const struct _MHD_cstr_w_len response_tk =
+    _MHD_S_STR_W_LEN ("response");
+  static const struct _MHD_cstr_w_len username_tk =
+    _MHD_S_STR_W_LEN ("username");
+  static const struct _MHD_cstr_w_len username_ext_tk =
+    _MHD_S_STR_W_LEN ("username*");
+  static const struct _MHD_cstr_w_len realm_tk = _MHD_S_STR_W_LEN ("realm");
+  static const struct _MHD_cstr_w_len uri_tk = _MHD_S_STR_W_LEN ("uri");
+  static const struct _MHD_cstr_w_len qop_tk = _MHD_S_STR_W_LEN ("qop");
+  static const struct _MHD_cstr_w_len cnonce_tk = _MHD_S_STR_W_LEN ("cnonce");
+  static const struct _MHD_cstr_w_len nc_tk = _MHD_S_STR_W_LEN ("nc");
+  static const struct _MHD_cstr_w_len userhash_tk =
+    _MHD_S_STR_W_LEN ("userhash");
+  struct MHD_RqDAuthParam userhash;
+  struct dauth_token_param map[] = {
+    {&nonce_tk, &(pdauth->nonce)},
+    {&opaque_tk, &(pdauth->opaque)},
+    {&algorithm_tk, &(pdauth->algorithm)},
+    {&response_tk, &(pdauth->response)},
+    {&username_tk, &(pdauth->username)},
+    {&username_ext_tk, &(pdauth->username_ext)},
+    {&realm_tk, &(pdauth->realm)},
+    {&uri_tk, &(pdauth->uri)},
+    {&qop_tk, &(pdauth->qop)},
+    {&cnonce_tk, &(pdauth->cnonce)},
+    {&nc_tk, &(pdauth->nc)},
+    {&userhash_tk, &userhash}
+  };
+  size_t i;
+  size_t p;
+
+  memset (&userhash, 0, sizeof(userhash));
+  i = 0;
+
+  /* Skip all whitespaces at start */
+  while (i < str_len && (' ' == str[i] || '\t' == str[i]))
+    i++;
+
+  while (str_len > i)
+  {
+    size_t left;
+    mhd_assert (' ' != str[i]);
+    mhd_assert ('\t' != str[i]);
+
+    left = str_len - i;
+    for (p = 0; p < sizeof(map) / sizeof(map[0]); p++)
+    {
+      struct dauth_token_param *const aparam = map + p;
+      if ( (aparam->tk_name->len < left) &&
+           MHD_str_equal_caseless_bin_n_ (str + i, aparam->tk_name->str,
+                                          aparam->tk_name->len) &&
+           (('=' == str[i + aparam->tk_name->len]) ||
+            (' ' == str[i + aparam->tk_name->len]) ||
+            ('\t' == str[i + aparam->tk_name->len])) )
+      {
+        size_t value_start;
+        size_t value_len;
+        bool quoted; /* Only mark as "quoted" if backslash-escape used */
+
+        quoted = false;
+        i += aparam->tk_name->len;
+        /* Skip all whitespaces before '=' */
+        while (str_len > i && (' ' == str[i] || '\t' == str[i]))
+          i++;
+        if ((i == str_len) || ('=' != str[i]))
+          return false; /* No equal sign, broken data */
+        i++;
+        /* Skip all whitespaces after '=' */
+        while (str_len > i && (' ' == str[i] || '\t' == str[i]))
+          i++;
+        if ((str_len > i) && ('"' == str[i]))
+        { /* Value is in quotation marks */
+          i++; /* Advance after the opening quote */
+          value_start = i;
+          while (str_len > i && '"' != str[i])
+          {
+            if ('\\' == str[i])
+            {
+              i++;
+              quoted = true; /* Have escaped chars */
+            }
+            if (0 == str[i])
+              return false; /* Binary zero in parameter value */
+            i++;
+          }
+          if (str_len <= i)
+            return false; /* No closing quote */
+          mhd_assert ('"' == str[i]);
+          value_len = i - value_start;
+          i++; /* Advance after the closing quote */
+        }
+        else
+        {
+          value_start = i;
+          while (str_len > i && ',' != str[i] &&
+                 ' ' != str[i] && '\t' != str[i] && ';' != str[i])
+          {
+            if (0 == str[i])
+              return false;  /* Binary zero in parameter value */
+            i++;
+          }
+          value_len = i - value_start;
+        }
+        /* Skip all whitespaces after parameter value */
+        while (str_len > i && (' ' == str[i] || '\t' == str[i]))
+          i++;
+        if ((str_len > i) && (',' != str[i]))
+          return false; /* Garbage after parameter value */
+
+        /* 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->quoted = quoted;
+
+        break; /* Found matching parameter name */
+      }
+    }
+    if (p == sizeof(map) / sizeof(map[0]))
+    {
+      /* No matching parameter name */
+      while (str_len > i && ',' != str[i])
+      {
+        if ('"' == str[i])
+        { /* Skip quoted part */
+          i++; /* Advance after the opening quote */
+          while (str_len > i && '"' != str[i])
+          {
+            if ('\\' == str[i])
+              i++; /* Skip escaped char */
+            i++;
+          }
+          if (str_len <= i)
+            return false; /* No closing quote */
+          mhd_assert ('"' == str[i]);
+        }
+        i++;
+      }
+    }
+    mhd_assert (str_len == i || ',' == str[i]);
+    if (str_len > i)
+      i++; /* Advance after ',' */
+    /* Skip all whitespaces before next parameter name */
+    while (i < str_len && (' ' == str[i] || '\t' == str[i]))
+      i++;
+  }
+
+  /* Postprocess values */
+  if ((NULL != userhash.value.str) && (0 != userhash.value.len))
+  {
+    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;
+    }
+    if ((param_len == 4) && MHD_str_equal_caseless_bin_n_ (param_str, "true",
+                                                           4))
+      pdauth->userhash = true;
+    else
+      pdauth->userhash = false;
+  }
+  else
+    pdauth->userhash = false;
+
+  return true;
+}
+
+
+#endif /* DAUTH_SUPPORT */
+
+
+/**
+ * Parse request "Authorization" header
+ * @param c the connection to process
+ * @return true if any supported Authorisation scheme were found,
+ *         false if no "Authorization" header found, no supported scheme found,
+ *         or an error occurred.
+ */
+_MHD_static_inline bool
+parse_auth_rq_header_ (struct MHD_Connection *c)
+{
+  const char *h; /**< The "Authorization" header */
+  size_t h_len;
+  struct MHD_AuthRqHeader *rq_auth;
+  size_t i;
+
+  mhd_assert (NULL == c->rq_auth);
+  mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= c->state);
+  if (MHD_CONNECTION_HEADERS_PROCESSED > c->state)
+    return false;
+
+  if (MHD_NO ==
+      MHD_lookup_connection_value_n (c, MHD_HEADER_KIND,
+                                     MHD_HTTP_HEADER_AUTHORIZATION,
+                                     MHD_STATICSTR_LEN_ ( \
+                                       MHD_HTTP_HEADER_AUTHORIZATION), &h,
+                                     &h_len))
+  {
+    rq_auth = (struct MHD_AuthRqHeader *)
+              MHD_connection_alloc_memory_ (c,
+                                            sizeof (struct MHD_AuthRqHeader));
+    c->rq_auth = rq_auth;
+    if (NULL != rq_auth)
+    {
+      memset (rq_auth, 0, sizeof(struct MHD_AuthRqHeader));
+      rq_auth->auth_type = MHD_AUTHTYPE_NONE;
+    }
+    return false;
+  }
+
+  rq_auth = NULL;
+  i = 0;
+  /* Skip the leading whitespace */
+  while (i < h_len)
+  {
+    const char ch = h[i];
+    if ((' ' != ch) && ('\t' != ch))
+      break;
+    i++;
+  }
+  h += i;
+  h_len -= i;
+
+#ifdef DAUTH_SUPPORT
+  if (1)
+  {
+    static const struct _MHD_cstr_w_len scheme_token =
+      _MHD_S_STR_W_LEN (_MHD_AUTH_DIGEST_BASE);
+
+    if ((scheme_token.len <= h_len) &&
+        MHD_str_equal_caseless_bin_n_ (h, scheme_token.str, scheme_token.len))
+    {
+      i = scheme_token.len;
+      /* RFC 7235 require only space after scheme token */
+      if ( (h_len <= i) ||
+           ((' ' == h[i]) || ('\t' == h[i])) ) /* Actually tab should NOT be 
allowed */
+      { /* Matched Digest authorisation scheme */
+        i++; /* Advance to the next char (even if it is beyond the end of the 
string) */
+
+        rq_auth = (struct MHD_AuthRqHeader *)
+                  MHD_connection_alloc_memory_ (c,
+                                                sizeof (struct 
MHD_AuthRqHeader)
+                                                + sizeof (struct MHD_RqDAuth));
+        c->rq_auth = rq_auth;
+        if (NULL == rq_auth)
+        {
+#ifdef HAVE_MESSAGES
+          MHD_DLOG (c->daemon,
+                    _ ("Failed to allocate memory in connection pool to " \
+                       "process \"" MHD_HTTP_HEADER_AUTHORIZATION "\" " \
+                       "header.\n"));
+#endif /* HAVE_MESSAGES */
+          return false;
+        }
+        memset (rq_auth, 0, sizeof (struct MHD_AuthRqHeader)
+                + sizeof (struct MHD_RqDAuth));
+        rq_auth->params.dauth = (struct MHD_RqDAuth *) (rq_auth + 1);
+
+        if (h_len > i)
+        {
+          if (! parse_dauth_params (h + i, h_len - i, rq_auth->params.dauth))
+          {
+            rq_auth->auth_type = MHD_AUTHTYPE_INVALID;
+            return false;
+          }
+        }
+
+        rq_auth->auth_type = MHD_AUTHTYPE_DIGEST;
+        return true;
+      }
+    }
+  }
+#endif /* DAUTH_SUPPORT */
+#ifdef BAUTH_SUPPORT
+  if (1)
+  {
+    static const struct _MHD_cstr_w_len scheme_token =
+      _MHD_S_STR_W_LEN (_MHD_AUTH_BASIC_BASE);
+
+    if ((scheme_token.len <= h_len) &&
+        MHD_str_equal_caseless_bin_n_ (h, scheme_token.str, scheme_token.len))
+    {
+      i = scheme_token.len;
+      /* RFC 7235 require only space after scheme token */
+      if ( (h_len <= i) ||
+           ((' ' == h[i]) || ('\t' == h[i])) ) /* Actually tab should NOT be 
allowed */
+      { /* Matched Basic authorisation scheme */
+        i++; /* Advance to the next char (even if it is beyond the end of the 
string) */
+
+        rq_auth = (struct MHD_AuthRqHeader *)
+                  MHD_connection_alloc_memory_ (c,
+                                                sizeof (struct 
MHD_AuthRqHeader)
+                                                + sizeof (struct MHD_RqBAuth));
+        c->rq_auth = rq_auth;
+        if (NULL == rq_auth)
+        {
+#ifdef HAVE_MESSAGES
+          MHD_DLOG (c->daemon,
+                    _ ("Failed to allocate memory in connection pool to " \
+                       "process \"" MHD_HTTP_HEADER_AUTHORIZATION "\" " \
+                       "header.\n"));
+#endif /* HAVE_MESSAGES */
+          return false;
+        }
+        memset (rq_auth, 0, sizeof (struct MHD_AuthRqHeader)
+                + sizeof (struct MHD_RqBAuth));
+        rq_auth->params.bauth = (struct MHD_RqBAuth *) (rq_auth + 1);
+
+        if (h_len > i)
+        {
+          if (! parse_bauth_params (h + i, h_len - i, rq_auth->params.bauth))
+          {
+            rq_auth->auth_type = MHD_AUTHTYPE_INVALID;
+            return false;
+          }
+        }
+
+        rq_auth->auth_type = MHD_AUTHTYPE_BASIC;
+        return true;
+      }
+    }
+  }
+#endif /* BAUTH_SUPPORT */
+
+  if (NULL == rq_auth)
+    rq_auth = (struct MHD_AuthRqHeader *)
+              MHD_connection_alloc_memory_ (c,
+                                            sizeof (struct MHD_AuthRqHeader));
+  c->rq_auth = rq_auth;
+  if (NULL != rq_auth)
+  {
+    memset (rq_auth, 0, sizeof(struct MHD_AuthRqHeader));
+    rq_auth->auth_type = MHD_AUTHTYPE_INVALID;
+  }
+  return false;
+}
+
+
+/**
+ * Return request's Authentication type and parameters.
+ *
+ * Function return result of parsing of the request's "Authorization" header or
+ * returns cached parsing result if the header was already parsed for
+ * the current request.
+ * @param connection the connection to process
+ * @return the pointer to structure with Authentication type and parameters,
+ *         NULL if no memory in memory pool or if called too early (before
+ *         header has been received).
+ */
+const struct MHD_AuthRqHeader *
+MHD_get_auth_rq_params_ (struct MHD_Connection *connection)
+{
+  mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= connection->state);
+
+  if (NULL != connection->rq_auth)
+    return connection->rq_auth;
+
+  if (MHD_CONNECTION_HEADERS_PROCESSED > connection->state)
+    return NULL;
+
+  parse_auth_rq_header_ (connection);
+
+  return connection->rq_auth;
+}
diff --git a/src/microhttpd/gen_auth.h b/src/microhttpd/gen_auth.h
new file mode 100644
index 00000000..6be4eb4d
--- /dev/null
+++ b/src/microhttpd/gen_auth.h
@@ -0,0 +1,93 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library.
+  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/gen_auth.h
+ * @brief  Declarations for HTTP authorisation general functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_GET_AUTH_H
+#define MHD_GET_AUTH_H 1
+
+#include "mhd_options.h"
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif /* HAVE_STDBOOL_H */
+
+struct MHD_Connection; /* Forward declaration to avoid include of the large 
headers */
+
+/**
+ * Type of authorisation
+ */
+enum MHD_AuthType
+{
+  MHD_AUTHTYPE_NONE = 0,/**< No authorisation */
+  MHD_AUTHTYPE_BASIC,   /**< Basic Authorisation, RFC 7617  */
+  MHD_AUTHTYPE_DIGEST,  /**< Digest Authorisation, RFC 7616 */
+  MHD_AUTHTYPE_INVALID  /**< Wrong/Unknown/Unsupported authorisation type */
+};
+
+#ifdef BAUTH_SUPPORT
+/* Forward declaration to avoid additional headers inclusion */
+struct MHD_RqBAuth;
+#endif /* BAUTH_SUPPORT */
+#ifdef DAUTH_SUPPORT
+/* Forward declaration to avoid additional headers inclusion */
+struct MHD_RqDAuth;
+#endif /* DAUTH_SUPPORT */
+
+/**
+ * Universal Authorisation Request parameters
+ */
+union MHD_AuthRqParams
+{
+#ifdef BAUTH_SUPPORT
+  struct MHD_RqBAuth *bauth;
+#endif /* BAUTH_SUPPORT */
+#ifdef DAUTH_SUPPORT
+  struct MHD_RqDAuth *dauth;
+#endif /* DAUTH_SUPPORT */
+};
+
+/**
+ * Request Authentication type and parameters
+ */
+struct MHD_AuthRqHeader
+{
+  enum MHD_AuthType auth_type;
+  union MHD_AuthRqParams params;
+};
+
+
+/**
+ * Return request's Authentication type and parameters.
+ *
+ * Function return result of parsing of the request's "Authorization" header or
+ * returns cached parsing result if the header was already parsed for
+ * the current request.
+ * @param connection the connection to process
+ * @return the pointer to structure with Authentication type and parameters,
+ *         NULL if no memory in memory pool or if called too early (before
+ *         header has been received).
+ */
+const struct MHD_AuthRqHeader *
+MHD_get_auth_rq_params_ (struct MHD_Connection *connection);
+
+#endif /* ! MHD_GET_AUTH_H */
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 3dafe866..f6452b2c 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -778,6 +778,8 @@ typedef ssize_t
                      size_t max_bytes);
 
 
+struct MHD_AuthRqHeader; /* Forward declaration only */
+
 /**
  * Ability to use same connection for next request
  */
@@ -1034,6 +1036,15 @@ struct MHD_Connection
    */
   enum MHD_HTTP_Version http_ver;
 
+#if defined(BAUTH_SUPPORT) || defined(DAUTH_SUPPORT)
+  /**
+   * Pointer to request authorization structure.
+   * Allocated in pool.
+   */
+  const struct MHD_AuthRqHeader *rq_auth;
+#endif
+
+
   /**
    * Close connection after sending response?
    * Functions may change value from "Unknown" or "KeepAlive" to "Must close",
diff --git a/src/testcurl/test_digestauth_concurrent.c 
b/src/testcurl/test_digestauth_concurrent.c
index 045b673d..adfe172d 100644
--- a/src/testcurl/test_digestauth_concurrent.c
+++ b/src/testcurl/test_digestauth_concurrent.c
@@ -567,7 +567,7 @@ testDigestAuth (void)
   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
     port = 0;
   else
-    port = 1165;
+    port = 4200;
 
   getRnd (rnd, sizeof(rnd));
 
diff --git a/w32/common/libmicrohttpd-files.vcxproj 
b/w32/common/libmicrohttpd-files.vcxproj
index 2fa2debc..391e1cec 100644
--- a/w32/common/libmicrohttpd-files.vcxproj
+++ b/w32/common/libmicrohttpd-files.vcxproj
@@ -6,6 +6,7 @@
     <ClCompile Include="$(MhdSrc)microhttpd\connection.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\daemon.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\digestauth.c" />
+    <ClCompile Include="$(MhdSrc)microhttpd\gen_auth.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\internal.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\md5.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\sha256.c" />
@@ -35,6 +36,7 @@
     <ClInclude Include="$(MhdSrc)microhttpd\basicauth.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\connection.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\digestauth.h" />
+    <ClInclude Include="$(MhdSrc)microhttpd\gen_auth.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\internal.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\md5.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\sha256.h" />
diff --git a/w32/common/libmicrohttpd-filters.vcxproj 
b/w32/common/libmicrohttpd-filters.vcxproj
index 684f8beb..16c6b085 100644
--- a/w32/common/libmicrohttpd-filters.vcxproj
+++ b/w32/common/libmicrohttpd-filters.vcxproj
@@ -52,6 +52,9 @@
     <ClInclude Include="$(MhdSrc)microhttpd\digestauth.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
+    <ClInclude Include="$(MhdSrc)microhttpd\gen_auth.h">
+      <Filter>Internal Headers</Filter>
+    </ClInclude>
     <ClInclude Include="$(MhdSrc)microhttpd\internal.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
@@ -135,6 +138,9 @@
     <ClCompile Include="$(MhdSrc)microhttpd\digestauth.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="$(MhdSrc)microhttpd\gen_auth.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="$(MhdSrc)microhttpd\internal.c">
       <Filter>Source Files</Filter>
     </ClCompile>

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