gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (1c181be2 -> 8b01c152)


From: gnunet
Subject: [libmicrohttpd] branch master updated (1c181be2 -> 8b01c152)
Date: Wed, 22 Jun 2022 20:00:06 +0200

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 1c181be2 Removed extra "Upgrade" token in Connection reply header in 
tests and examples
     new 14228333 configure: removed unneeded special flags for Darwin
     new 2286bbe1 configure: added basic support for AIX XLC flags
     new 299fdcd2 configure: removed unused variable
     new 5ba4b770 test_digestauth{._with_arguments}: do test really with 
arguments
     new 6ccaa5da MHD_parse_arguments_(): refactored, allow cls for the callback
     new a5af7f73 digest_auth_check_all(): simplified, improved readability
     new c4246b52 Added tracking of the request URL length.
     new 1efb758b Fixed check for URL match to handle URLs with binary zero
     new 348945c3 digestauth: removed now unused do-while scope
     new da3457ea digestauth.h: added some doxy
     new 8b01c152 mhd_str.h: fixed doxy

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


Summary of changes:
 configure.ac                                  |   6 +-
 src/include/microhttpd.h                      |  24 +-
 src/microhttpd/connection.c                   |  23 +-
 src/microhttpd/digestauth.c                   | 935 +++++++++++++-------------
 src/microhttpd/digestauth.h                   |  17 +
 src/microhttpd/internal.c                     |  17 +-
 src/microhttpd/internal.h                     |  13 +-
 src/microhttpd/mhd_str.h                      |  13 +-
 src/testcurl/test_digestauth.c                |   2 +-
 src/testcurl/test_digestauth_with_arguments.c |   3 +-
 10 files changed, 533 insertions(+), 520 deletions(-)

diff --git a/configure.ac b/configure.ac
index f505aa0c..871df81c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -254,7 +254,9 @@ AC_MSG_RESULT([${enable_compact_code} 
(${compact_code_MSG})])
 
 CFLAGS="${user_CFLAGS}"
 # Compiler options to always enable (if supported)
-MHD_CHECK_ADD_CC_CFLAG([-fno-strict-aliasing], [CFLAGS_ac])
+MHD_FIND_ADD_CC_CFLAG([CFLAGS_ac], [-fno-strict-aliasing], [-qnoansialias])
+# '-qlonglong' is XLC option for C89, not used with C99 or later
+MHD_CHECK_ADD_CC_CFLAG([-qlonglong], [CFLAGS_ac])
 
 AS_VAR_IF([enable_build_type],["neutral"],[],
   [ # Any non-neutral build types
@@ -757,12 +759,10 @@ AS_VAR_IF([mhd_cv_c_alignof], ["yes"],
 
 
 # Check system type
-shutdown_trig_select='no'
 AC_MSG_CHECKING([[for target host OS]])
 AS_CASE(["$host_os"],
  [*darwin* | *rhapsody* | *macosx*],
  [AC_DEFINE([OSX],[1],[This is an OS X system])
-     CFLAGS_ac="-no-cpp-precomp -fno-common $CFLAGS_ac"
      mhd_host_os='Darwin'
      AC_MSG_RESULT([[$mhd_host_os]])],
  [kfreebsd*-gnu],
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 8a6fea2f..2eb6e05c 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 0x00097517
+#define MHD_VERSION 0x00097518
 
 /* If generic headers don't work on your platform, include headers
    which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -4376,7 +4376,7 @@ enum MHD_DigestAuthAlgorithm
  *
  * All error values are zero or negative.
  *
- * @note Available since #MHD_VERSION 0x00097513
+ * @note Available since #MHD_VERSION 0x00097518
  */
 enum MHD_DigestAuthResult
 {
@@ -4410,25 +4410,35 @@ enum MHD_DigestAuthResult
    */
   MHD_DAUTH_WRONG_URI = -4,
 
+  /**
+   * Wrong 'qop'.
+   */
+  MHD_DAUTH_WRONG_QOP = -5,
+
+  /**
+   * Too large (>64 KiB) Authorization parameter value.
+   */
+  MHD_DAUTH_TOO_LARGE = -15,
+
   /* The different form of naming is intentionally used for the results below,
    * as they are more important */
 
   /**
    * The 'nonce' is too old. Suggest the client to retry with the same
    * username and password to get the fresh 'nonce'.
-   * The validity of the 'nonce' may not be checked.
+   * The validity of the 'nonce' may be not checked.
    */
-  MHD_DAUTH_NONCE_STALE = -16,
+  MHD_DAUTH_NONCE_STALE = -17,
 
   /**
    * The 'nonce' is wrong. May indicate an attack attempt.
    */
-  MHD_DAUTH_NONCE_WRONG = -32,
+  MHD_DAUTH_NONCE_WRONG = -33,
 
   /**
    * The 'response' is wrong. May indicate an attack attempt.
    */
-  MHD_DAUTH_RESPONSE_WRONG = -33,
+  MHD_DAUTH_RESPONSE_WRONG = -34,
 };
 
 
@@ -4443,7 +4453,7 @@ enum MHD_DigestAuthResult
  * @param algo the digest algorithms allowed for verification
  * @return #MHD_DAUTH_OK if authenticated,
  *         the error code otherwise
- * @note Available since #MHD_VERSION 0x00097513
+ * @note Available since #MHD_VERSION 0x00097518
  * @ingroup authentication
  */
 _MHD_EXTERN enum MHD_DigestAuthResult
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 2d58e35c..9068ee08 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -2427,6 +2427,7 @@ transmit_error_response_len (struct MHD_Connection 
*connection,
     connection->version = NULL;
     connection->method = NULL;
     connection->url = NULL;
+    connection->url_len = 0;
     connection->last = NULL;
     connection->colon = NULL;
     connection->headers_received = NULL;
@@ -2725,8 +2726,7 @@ get_next_header_line (struct MHD_Connection *connection,
  * Add an entry to the HTTP headers of a connection.  If this fails,
  * transmit an error response (request too big).
  *
- * @param connection the connection for which a
- *  value should be set
+ * @param cls the context (connection)
  * @param kind kind of the value
  * @param key key for the value
  * @param key_size number of bytes in @a key
@@ -2735,13 +2735,14 @@ get_next_header_line (struct MHD_Connection *connection,
  * @return #MHD_NO on failure (out of memory), #MHD_YES for success
  */
 static enum MHD_Result
-connection_add_header (struct MHD_Connection *connection,
+connection_add_header (void *cls,
                        const char *key,
                        size_t key_size,
                        const char *value,
                        size_t value_size,
                        enum MHD_ValueKind kind)
 {
+  struct MHD_Connection *connection = (struct MHD_Connection *) cls;
   if (MHD_NO ==
       MHD_set_connection_value_n (connection,
                                   kind,
@@ -3266,7 +3267,6 @@ parse_initial_message_line (struct MHD_Connection 
*connection,
   char *uri;
   char *http_version;
   char *args;
-  unsigned int unused_num_headers;
 
   if (NULL == (uri = memchr (line,
                              ' ',
@@ -3362,14 +3362,20 @@ parse_initial_message_line (struct MHD_Connection 
*connection,
                           MHD_GET_ARGUMENT_KIND,
                           args,
                           &connection_add_header,
-                          &unused_num_headers);
+                          connection);
   }
 
   /* unescape URI *after* searching for arguments and log callback */
   if (NULL != uri)
-    daemon->unescape_callback (daemon->unescape_callback_cls,
-                               connection,
-                               uri);
+  {
+    connection->url_len =
+      daemon->unescape_callback (daemon->unescape_callback_cls,
+                                 connection,
+                                 uri);
+  }
+  else
+    connection->url_len = 0;
+
   connection->url = curi;
   return MHD_YES;
 }
@@ -4756,6 +4762,7 @@ connection_reset (struct MHD_Connection *connection,
     c->method = NULL;
     c->http_mthd = MHD_HTTP_MTHD_NO_METHOD;
     c->url = NULL;
+    c->url_len = 0;
     memset (&c->rp_props, 0, sizeof(c->rp_props));
     c->write_buffer = NULL;
     c->write_buffer_size = 0;
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 890fc129..e6f68222 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -134,7 +134,7 @@
 /**
  * Maximum length of the response in digest authentication.
  */
-#define MAX_AUTH_RESPONSE_LENGTH 256
+#define MAX_AUTH_RESPONSE_LENGTH (MAX_DIGEST * 2)
 
 /**
  * The token for MD5 algorithm.
@@ -1185,11 +1185,17 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
 }
 
 
+struct test_header_param
+{
+  struct MHD_Connection *connection;
+  unsigned int num_headers;
+};
+
 /**
  * Test if the given key-value pair is in the headers for the
  * given connection.
  *
- * @param connection the connection
+ * @param cls the test context
  * @param key the key
  * @param key_size number of bytes in @a key
  * @param value the value, can be NULL
@@ -1199,15 +1205,18 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
  *         #MHD_NO if not
  */
 static enum MHD_Result
-test_header (struct MHD_Connection *connection,
+test_header (void *cls,
              const char *key,
              size_t key_size,
              const char *value,
              size_t value_size,
              enum MHD_ValueKind kind)
 {
+  struct test_header_param *const param = (struct test_header_param *) cls;
+  struct MHD_Connection *connection = param->connection;
   struct MHD_HTTP_Req_Header *pos;
 
+  param->num_headers++;
   for (pos = connection->headers_received; NULL != pos; pos = pos->next)
   {
     if (kind != pos->kind)
@@ -1251,8 +1260,8 @@ check_argument_match (struct MHD_Connection *connection,
 {
   struct MHD_HTTP_Req_Header *pos;
   char *argb;
-  unsigned int num_headers;
   enum MHD_Result ret;
+  struct test_header_param param;
 
   argb = strdup (args);
   if (NULL == argb)
@@ -1263,11 +1272,13 @@ check_argument_match (struct MHD_Connection *connection,
 #endif /* HAVE_MESSAGES */
     return MHD_NO;
   }
+  param.connection = connection;
+  param.num_headers = 0;
   ret = MHD_parse_arguments_ (connection,
                               MHD_GET_ARGUMENT_KIND,
                               argb,
                               &test_header,
-                              &num_headers);
+                              &param);
   free (argb);
   if (MHD_NO == ret)
   {
@@ -1278,9 +1289,9 @@ check_argument_match (struct MHD_Connection *connection,
   {
     if (MHD_GET_ARGUMENT_KIND != pos->kind)
       continue;
-    num_headers--;
+    param.num_headers--;
   }
-  if (0 != num_headers)
+  if (0 != param.num_headers)
   {
     /* argument count mismatch */
     return MHD_NO;
@@ -1294,19 +1305,56 @@ check_argument_match (struct MHD_Connection *connection,
  */
 #define _MHD_STATIC_UNQ_BUFFER_SIZE 128
 
+
 /**
- * The result of parameter unquoting
+ * Get the pointer to buffer with required size
+ * @param tmp1 the first buffer with fixed size
+ * @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 required_size the required size in buffer
+ * @return the pointer to the buffer or NULL if failed to allocate buffer with
+ *         requested size
  */
+static char *
+get_buffer_for_size (char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
+                     char **ptmp2,
+                     size_t *ptmp2_size,
+                     size_t required_size)
+{
+  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 (required_size <= _MHD_STATIC_UNQ_BUFFER_SIZE)
+    return tmp1;
+
+  if (required_size <= *ptmp2_size)
+    return *ptmp2;
+
+  if (required_size > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
+    return NULL;
+  if (NULL != *ptmp2)
+    free (*ptmp2);
+  *ptmp2 = (char *) malloc (required_size);
+  if (NULL == *ptmp2)
+    *ptmp2_size = 0;
+  else
+    *ptmp2_size = required_size;
+  return *ptmp2;
+}
+
+
+/**
+  * 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 */
+  _MHD_UNQ_OK = 0,         /**< Got unquoted string */
+  _MHD_UNQ_TOO_LARGE = -7, /**< 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
@@ -1317,60 +1365,79 @@ enum _MHD_GetUnqResult
  * @return enum code indicating result of the process
  */
 static enum _MHD_GetUnqResult
-get_unqouted_param (const struct MHD_RqDAuthParam *param,
+get_unquoted_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)
+                    struct _MHD_str_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));
+  mhd_assert (NULL != param->value.str);
+  mhd_assert (0 != param->value.len);
 
-  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;
+    unquoted->str = param->value.str;
+    unquoted->len = param->value.len;
+    return _MHD_UNQ_OK;
   }
   /* 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;
-  }
+  str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
+  if (NULL == str)
+    return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
+           _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
 
   len = MHD_str_unquote (param->value.str, param->value.len, str);
-  if (1)
+  unquoted->str = str;
+  unquoted->len = len;
+  mhd_assert (0 != unquoted->len);
+  mhd_assert (unquoted->len < param->value.len);
+  return _MHD_UNQ_OK;
+}
+
+
+/**
+ * Get copy of 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,
+ *                      but with enough space to zero-terminate
+ * @return enum code indicating result of the process
+ */
+static enum _MHD_GetUnqResult
+get_unquoted_param_copy (const struct MHD_RqDAuthParam *param,
+                         char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
+                         char **ptmp2,
+                         size_t *ptmp2_size,
+                         struct _MHD_mstr_w_len *unquoted)
+{
+  mhd_assert (NULL != param->value.str);
+  mhd_assert (0 != param->value.len);
+
+  /* The value is present and is quoted, needs to be copied and unquoted */
+  /* Allocate buffer with one more additional byte for zero-termination */
+  unquoted->str =
+    get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
+
+  if (NULL == unquoted->str)
+    return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
+           _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
+
+  if (! param->quoted)
   {
-    const struct _MHD_cstr_w_len res = {str, len};
-    memcpy (unquoted, &res, sizeof(res));
+    memcpy (unquoted->str, param->value.str, param->value.len);
+    unquoted->len = param->value.len;
+    return _MHD_UNQ_OK;
   }
+
+  unquoted->len =
+    MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
   mhd_assert (0 != unquoted->len);
   mhd_assert (unquoted->len < param->value.len);
-  return _MHD_UNQ_NON_EMPTY;
+  return _MHD_UNQ_OK;
 }
 
 
@@ -1413,18 +1480,21 @@ is_param_equal (const struct MHD_RqDAuthParam *param,
  *     (must contain "da->digest_size" bytes or be NULL)
  * @param nonce_timeout The amount of time for a nonce to be
  *      invalid in seconds
+ * @param[out] pbuf the pointer to pointer to internally malloc'ed buffer,
+ *                  to be free if not NULL upon return
  * @return #MHD_DAUTH_OK if authenticated,
  *         error code otherwise.
  * @ingroup authentication
  */
 static enum MHD_DigestAuthResult
-digest_auth_check_all (struct MHD_Connection *connection,
-                       struct DigestAlgorithm *da,
-                       const char *realm,
-                       const char *username,
-                       const char *password,
-                       const uint8_t *digest,
-                       unsigned int nonce_timeout)
+digest_auth_check_all_inner (struct MHD_Connection *connection,
+                             struct DigestAlgorithm *da,
+                             const char *realm,
+                             const char *username,
+                             const char *password,
+                             const uint8_t *digest,
+                             unsigned int nonce_timeout,
+                             char **pbuf)
 {
   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
   char cnonce[MAX_CLIENT_NONCE_LENGTH];
@@ -1441,478 +1511,377 @@ digest_auth_check_all (struct MHD_Connection 
*connection,
   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 */
+  char **const ptmp2 = pbuf;     /**< Temporal malloc'ed buffer for unqouting 
*/
   size_t tmp2_size; /**< The size of @a tmp2 buffer */
-  struct _MHD_cstr_w_len unquoted;
+  struct _MHD_str_w_len unquoted;
+  struct _MHD_mstr_w_len unq_copy;
   enum _MHD_GetUnqResult unq_res;
   enum MHD_DigestAuthResult ret;
-#ifdef HAVE_MESSAGES
-  bool err_logged;
-#endif /* HAVE_MESSAGES */
   size_t username_len;
   size_t realm_len;
 
-  tmp2 = NULL;
   tmp2_size = 0;
-#ifdef HAVE_MESSAGES
-  err_logged = false;
-#endif /* HAVE_MESSAGES */
-
-  do /* Only to avoid "goto" */
-  {
-
-    params = get_rq_dauth_params (connection);
-    if (NULL == params)
-    {
-      ret = MHD_DAUTH_WRONG_HEADER;
-      break;
-    }
 
-    /* Check 'username' */
-    if (NULL == params->username.value.str)
-    {
-      ret = MHD_DAUTH_WRONG_HEADER;
-      break;
-    }
-    username_len = strlen (username);
-    if (! is_param_equal (&params->username, username, username_len))
-    {
-      ret = MHD_DAUTH_WRONG_USERNAME;
-      break;
-    }
-    /* 'username' valid */
+  params = get_rq_dauth_params (connection);
+  if (NULL == params)
+    return MHD_DAUTH_WRONG_HEADER;
 
-    /* Check 'realm' */
-    if (NULL == params->realm.value.str)
-    {
-      ret = MHD_DAUTH_WRONG_HEADER;
-      break;
-    }
-    realm_len = strlen (realm);
-    if (! is_param_equal (&params->realm, realm, realm_len))
-    {
-      ret = MHD_DAUTH_WRONG_REALM;
-      break;
-    }
-    /* 'realm' valid */
+  /* Check 'username' */
+  if (NULL == params->username.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+
+  username_len = strlen (username);
+  if (! is_param_equal (&params->username, username, username_len))
+    return MHD_DAUTH_WRONG_USERNAME;
+  /* 'username' valid */
+
+  /* Check 'realm' */
+  if (NULL == params->realm.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  realm_len = strlen (realm);
+  if (! is_param_equal (&params->realm, realm, realm_len))
+    return MHD_DAUTH_WRONG_REALM;
+  /* 'realm' valid */
+
+  /* Check 'nonce' */
+  if (NULL == params->nonce.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->nonce.value.len)
+    return MHD_DAUTH_NONCE_WRONG;
+  else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
+    return MHD_DAUTH_NONCE_WRONG;
+
+  unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
+                                &unquoted);
+  if (_MHD_UNQ_OK != unq_res)
+    return MHD_DAUTH_ERROR;
+  if (NONCE_STD_LEN (digest_size) != unquoted.len)
+    return MHD_DAUTH_NONCE_WRONG;
+
+  if (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time))
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _ ("Authentication failed, invalid timestamp format.\n"));
+#endif
+    return MHD_DAUTH_NONCE_WRONG;
+  }
+  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))
+    return MHD_DAUTH_NONCE_STALE; /* too old */
 
-    /* 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))
-    {
+  calculate_nonce (nonce_time,
+                   connection->method,
+                   daemon->digest_auth_random,
+                   daemon->digest_auth_rand_size,
+                   connection->url,
+                   realm,
+                   realm_len,
+                   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 != strncmp (noncehashexp, unquoted.str, unquoted.len)) ||
+      (0 != noncehashexp[unquoted.len]))
+    return MHD_DAUTH_NONCE_WRONG;
+  /* 'nonce' valid */
+
+  /* Get 'cnonce' */
+  if (NULL == params->cnonce.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->cnonce.value.len)
+    return MHD_DAUTH_WRONG_HEADER;
+  unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
+                                &unquoted);
+  if (_MHD_UNQ_OK != unq_res)
+    return (_MHD_UNQ_TOO_LARGE == unq_res) ?
+           MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
+
+  if (sizeof(cnonce) <= unquoted.len)
+    return MHD_DAUTH_ERROR; /* TODO: handle large client nonces */
+
+  /* TODO: avoid memcpy() */
+  memcpy (cnonce, unquoted.str, unquoted.len);
+  cnonce[unquoted.len] = 0;
+  /* Got 'cnonce' */
+
+  /* Get 'qop' */
+  if (NULL == params->qop.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->qop.value.len)
+    return MHD_DAUTH_WRONG_QOP;
+  else if (MHD_STATICSTR_LEN_ ("auth-int") * 2 < params->qop.value.len)
+    return MHD_DAUTH_WRONG_QOP;
+  unq_res = get_unquoted_param (&params->qop, tmp1, ptmp2, &tmp2_size,
+                                &unquoted);
+  if (_MHD_UNQ_OK != unq_res)
+    return MHD_DAUTH_ERROR;
+
+  if (sizeof(qop) <= unquoted.len)
+    return MHD_DAUTH_ERROR; /* TODO: handle large client qop */
+  /* TODO: avoid memcpy() */
+  memcpy (qop, unquoted.str, unquoted.len);
+  qop[unquoted.len] = 0;
+  /* TODO: Really support empty value, support "auth-int" */
+  if ( ((MHD_STATICSTR_LEN_ ("auth") != unquoted.len) ||
+        (! MHD_str_equal_caseless_bin_n_ (qop, "auth", unquoted.len))) &&
+       (0 != strcmp (qop,"")) )
+    return MHD_DAUTH_WRONG_QOP;
+  /* Got 'qop' */
+
+  /* Get 'nc' */
+  if (NULL == params->nc.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->nc.value.len)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (4 * 8 < params->nc.value.len) /* Four time more than needed */
+    return MHD_DAUTH_NONCE_WRONG;
+  unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
+                                &unquoted);
+  if (_MHD_UNQ_OK != unq_res)
+    return MHD_DAUTH_ERROR;
+
+  if (sizeof(nc) <= unquoted.len)
+    return MHD_DAUTH_ERROR;
+  /* 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,
-                _ ("Authentication failed, invalid timestamp format.\n"));
-      err_logged = true;
+    MHD_DLOG (daemon,
+              _ ("Authentication failed, invalid nc format.\n"));
 #endif
-      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;
-    }
+    return MHD_DAUTH_WRONG_HEADER;   /* invalid nonce format */
+  }
+  if (0 == nci)
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _ ("Authentication failed, invalid 'nc' value.\n"));
+#endif
+    return MHD_DAUTH_WRONG_HEADER;   /* invalid nc value */
+  }
+  /* Got 'nc' */
+
+  /* Get 'response' */
+  if (NULL == params->response.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->response.value.len)
+    return MHD_DAUTH_RESPONSE_WRONG;
+  else if (digest_size * 4 < params->response.value.len)
+    return MHD_DAUTH_RESPONSE_WRONG;
+  unq_res = get_unquoted_param (&params->response, tmp1, ptmp2, &tmp2_size,
+                                &unquoted);
+  if (_MHD_UNQ_OK != unq_res)
+    return MHD_DAUTH_ERROR;
+  if (digest_size * 2 != unquoted.len)
+    return MHD_DAUTH_RESPONSE_WRONG;
+
+  mhd_assert (sizeof(response) > unquoted.len);
+
+  if (sizeof(response) <= unquoted.len)
+    return MHD_DAUTH_ERROR;
+  /* TODO: avoid memcpy() */
+  memcpy (response, unquoted.str, unquoted.len);
+  response[unquoted.len] = 0;
+  /* Got 'response' */
 
-    calculate_nonce (nonce_time,
-                     connection->method,
-                     daemon->digest_auth_random,
-                     daemon->digest_auth_rand_size,
-                     connection->url,
-                     realm,
-                     realm_len,
-                     da,
-                     noncehashexp);
+  if (1)
+  {
+    enum MHD_CheckNonceNC_ nonce_nc_check;
     /*
-     * 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.
+     * Checking if that combination of nonce and nc is sound
+     * and not a replay attack attempt. Refuse if nonce was not
+     * generated previously.
      */
-    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))
+    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,
-                _ ("Authentication failed, invalid nc format.\n"));
-      err_logged = true;
+                _ ("Stale nonce received. If this happens a lot, you should "
+                   "probably increase the size of the nonce array.\n"));
 #endif
-      ret = MHD_DAUTH_WRONG_HEADER;   /* invalid nonce format */
-      break;
+      return MHD_DAUTH_NONCE_STALE;
     }
-    if (0 == nci)
+    else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
     {
 #ifdef HAVE_MESSAGES
       MHD_DLOG (daemon,
-                _ ("Authentication failed, invalid 'nc' value.\n"));
-      err_logged = true;
+                _ ("Received nonce that technically valid, but was not "
+                   "generated by MHD. This may indicate an attack 
attempt.\n"));
 #endif
-      ret = MHD_DAUTH_WRONG_HEADER;   /* invalid nc value */
-      break;
-    }
-    /* Got 'nc' */
-
-    /* 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;
+      return MHD_DAUTH_NONCE_WRONG;
     }
-    /* TODO: avoid memcpy() */
-    memcpy (response, unquoted.str, unquoted.len);
-    response[unquoted.len] = 0;
-    /* Got 'response' */
+    mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
+  }
 
-    if (1)
+  /* Get 'uri' */
+  if (NULL == params->uri.value.str)
+    return MHD_DAUTH_WRONG_HEADER;
+  else if (0 == params->uri.value.len)
+    return MHD_DAUTH_WRONG_URI;
+  unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
+                                     &unq_copy);
+  if (_MHD_UNQ_OK != unq_res)
+    return (_MHD_UNQ_TOO_LARGE == unq_res) ?
+           MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
+
+  if (NULL != digest)
+  {
+    /* This will initialize da->digest_hex (ha1) */
+    digest_calc_ha1_from_digest (digest_get_algo_name (da),
+                                 da,
+                                 digest,
+                                 noncehashexp,
+                                 cnonce);
+  }
+  else
+  {
+    /* This will initialize da->digest_hex (ha1) */
+    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,
+                               da);
+  }
+  memcpy (ha1,
+          digest_get_hex_buffer (da),
+          digest_size * 2 + 1);
+  /* This will initialize da->sessionkey (respexp) */
+  digest_calc_response (ha1,
+                        noncehashexp,
+                        nc,
+                        cnonce,
+                        qop,
+                        connection->method,
+                        unq_copy.str,
+                        unq_copy.len,
+                        hentity,
+                        da);
+  if (1)
+  {
+    char *uri;
+    size_t uri_len;
+    uri = unq_copy.str;
+    uri_len = unq_copy.len;
+
+    uri[uri_len] = 0;
+    qmark = memchr (uri,
+                    '?',
+                    uri_len);
+    if (NULL != qmark)
+      *qmark = '\0';
+
+    /* Need to unescape URI before comparing with connection->url */
+    uri_len = daemon->unescape_callback (daemon->unescape_callback_cls,
+                                         connection,
+                                         uri);
+    if ((uri_len != connection->url_len) ||
+        (0 != memcmp (uri, connection->url, uri_len)))
     {
-      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,
-                  _ ("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;
+      MHD_DLOG (daemon,
+                _ ("Authentication failed, URI does not match.\n"));
 #endif
-        ret = MHD_DAUTH_NONCE_WRONG;
-        break;
-      }
-      mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
+      return MHD_DAUTH_WRONG_URI;
     }
 
-    /* Get 'uri' */
-    unq_res = get_unqouted_param (&params->uri, 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 (NULL != digest)
-    {
-      /* This will initialize da->digest_hex (ha1) */
-      digest_calc_ha1_from_digest (digest_get_algo_name (da),
-                                   da,
-                                   digest,
-                                   noncehashexp,
-                                   cnonce);
-    }
-    else
-    {
-      /* This will initialize da->digest_hex (ha1) */
-      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,
-                                 da);
-    }
-    memcpy (ha1,
-            digest_get_hex_buffer (da),
-            digest_size * 2 + 1);
-    /* This will initialize da->sessionkey (respexp) */
-    digest_calc_response (ha1,
-                          noncehashexp,
-                          nc,
-                          cnonce,
-                          qop,
-                          connection->method,
-                          unquoted.str,
-                          unquoted.len,
-                          hentity,
-                          da);
     if (1)
     {
-      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
-      {
-        mhd_assert (tmp2 == unquoted.str);
-        uri = tmp2;
-      }
+      const char *args = qmark;
 
-      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))
+      if (NULL == args)
+        args = "";
+      else
+        args++;
+      if (MHD_NO ==
+          check_argument_match (connection,
+                                args) )
       {
 #ifdef HAVE_MESSAGES
         MHD_DLOG (daemon,
-                  _ ("Authentication failed, URI does not match.\n"));
-        err_logged = true;
+                  _ ("Authentication failed, arguments do not match.\n"));
 #endif
-        ret = MHD_DAUTH_WRONG_URI;
-        break;
+        return MHD_DAUTH_WRONG_URI;
       }
-
-      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;
     }
-  } while (0);
-  if (NULL != tmp2)
-    free (tmp2);
 
-  if ((MHD_DAUTH_OK != ret) && ! err_logged)
-  {
-    (void) 0; /* TODO: add logging */
+    ret = (0 == strcmp (response,
+                        digest_get_hex_buffer (da)))
+    ? MHD_DAUTH_OK
+    : MHD_DAUTH_RESPONSE_WRONG;
   }
 
   return ret;
 }
 
 
+/**
+ * Authenticates the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @param[in,out] da digest algorithm to use for checking (written to as
+ *         part of the calculations, but the values left in the struct
+ *         are not actually expected to be useful for the caller)
+ * @param realm The realm presented to the client
+ * @param username The username needs to be authenticated
+ * @param password The password used in the authentication
+ * @param digest An optional binary hash
+ *     of the precalculated hash value "username:realm:password"
+ *     (must contain "da->digest_size" bytes or be NULL)
+ * @param nonce_timeout The amount of time for a nonce to be
+ *      invalid in seconds
+ * @return #MHD_DAUTH_OK if authenticated,
+ *         error code otherwise.
+ * @ingroup authentication
+ */
+static enum MHD_DigestAuthResult
+digest_auth_check_all (struct MHD_Connection *connection,
+                       struct DigestAlgorithm *da,
+                       const char *realm,
+                       const char *username,
+                       const char *password,
+                       const uint8_t *digest,
+                       unsigned int nonce_timeout)
+{
+  enum MHD_DigestAuthResult res;
+  char *buf;
+
+  buf = NULL;
+  res = digest_auth_check_all_inner (connection, da, realm, username, password,
+                                     digest, nonce_timeout, &buf);
+  if (NULL != buf)
+    free (buf);
+
+  return res;
+}
+
+
 /**
  * Authenticates the authorization header sent by the client.
  * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility).
diff --git a/src/microhttpd/digestauth.h b/src/microhttpd/digestauth.h
index 367e8e01..af54bc63 100644
--- a/src/microhttpd/digestauth.h
+++ b/src/microhttpd/digestauth.h
@@ -49,12 +49,26 @@
  */
 #define _MHD_AUTH_DIGEST_BASE   "Digest"
 
+/**
+ * Parameter of request's Digest Authorization header
+ */
 struct MHD_RqDAuthParam
 {
+  /**
+   * The string with length, NOT zero-terminated
+   */
   struct _MHD_str_w_len value;
+  /**
+   * True if string must be "unquoted" before processing.
+   * This member is false if the string is used in DQUOTE marks, but no
+   * backslash-escape is used in the string.
+   */
   bool quoted;
 };
 
+/**
+ * Request client's Digest Authorization header parameters
+ */
 struct MHD_RqDAuth
 {
   struct MHD_RqDAuthParam nonce;
@@ -68,6 +82,9 @@ struct MHD_RqDAuth
   struct MHD_RqDAuthParam qop;
   struct MHD_RqDAuthParam cnonce;
   struct MHD_RqDAuthParam nc;
+  /**
+   * True if 'userhash' parameter is used with value 'true'.
+   */
   bool userhash;
 };
 
diff --git a/src/microhttpd/internal.c b/src/microhttpd/internal.c
index b1e2ad36..e9e92414 100644
--- a/src/microhttpd/internal.c
+++ b/src/microhttpd/internal.c
@@ -186,7 +186,7 @@ MHD_http_unescape (char *val)
  * @param[in,out] args argument URI string (after "?" in URI),
  *        clobbered in the process!
  * @param cb function to call on each key-value pair found
- * @param[out] num_headers set to the number of headers found
+ * @param cls the iterator context
  * @return #MHD_NO on failure (@a cb returned #MHD_NO),
  *         #MHD_YES for success (parsing succeeded, @a cb always
  *                               returned #MHD_YES)
@@ -196,13 +196,12 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
                       enum MHD_ValueKind kind,
                       char *args,
                       MHD_ArgumentIterator_ cb,
-                      unsigned int *num_headers)
+                      void *cls)
 {
   struct MHD_Daemon *daemon = connection->daemon;
   char *equals;
   char *amper;
 
-  *num_headers = 0;
   while ( (NULL != args) &&
           ('\0' != args[0]) )
   {
@@ -220,14 +219,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
         key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                              connection,
                                              args);
-        if (MHD_NO == cb (connection,
+        if (MHD_NO == cb (cls,
                           args,
                           key_len,
                           NULL,
                           0,
                           kind))
           return MHD_NO;
-        (*num_headers)++;
         break;
       }
       /* got 'foo=bar' */
@@ -241,14 +239,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
       value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                              connection,
                                              equals);
-      if (MHD_NO == cb (connection,
+      if (MHD_NO == cb (cls,
                         args,
                         key_len,
                         equals,
                         value_len,
                         kind))
         return MHD_NO;
-      (*num_headers)++;
       break;
     }
     /* amper is non-NULL here */
@@ -262,7 +259,7 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
       key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                            connection,
                                            args);
-      if (MHD_NO == cb (connection,
+      if (MHD_NO == cb (cls,
                         args,
                         key_len,
                         NULL,
@@ -270,7 +267,6 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
                         kind))
         return MHD_NO;
       /* continue with 'bar' */
-      (*num_headers)++;
       args = amper;
       continue;
     }
@@ -286,14 +282,13 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
     value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                            connection,
                                            equals);
-    if (MHD_NO == cb (connection,
+    if (MHD_NO == cb (cls,
                       args,
                       key_len,
                       equals,
                       value_len,
                       kind))
       return MHD_NO;
-    (*num_headers)++;
     args = amper;
   }
   return MHD_YES;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 79b93c80..6906e1bb 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -1033,6 +1033,11 @@ struct MHD_Connection
    */
   const char *url;
 
+  /**
+   * The length of the @a url in characters, not including the terminating 
zero.
+   */
+  size_t url_len;
+
   /**
    * HTTP version string (i.e. http/1.1).  Allocated
    * in pool.
@@ -2368,7 +2373,7 @@ MHD_unescape_plus (char *arg);
  * Callback invoked when iterating over @a key / @a value
  * argument pairs during parsing.
  *
- * @param connection context of the iteration
+ * @param cls context of the iteration
  * @param key 0-terminated key string, never NULL
  * @param key_size number of bytes in key
  * @param value 0-terminated binary data, may include binary zeros, may be NULL
@@ -2378,7 +2383,7 @@ MHD_unescape_plus (char *arg);
  *         #MHD_NO to signal failure (and abort iteration)
  */
 typedef enum MHD_Result
-(*MHD_ArgumentIterator_)(struct MHD_Connection *connection,
+(*MHD_ArgumentIterator_)(void *cls,
                          const char *key,
                          size_t key_size,
                          const char *value,
@@ -2395,7 +2400,7 @@ typedef enum MHD_Result
  * @param[in,out] args argument URI string (after "?" in URI),
  *        clobbered in the process!
  * @param cb function to call on each key-value pair found
- * @param[out] num_headers set to the number of headers found
+ * @param cls the iterator context
  * @return #MHD_NO on failure (@a cb returned #MHD_NO),
  *         #MHD_YES for success (parsing succeeded, @a cb always
  *                               returned #MHD_YES)
@@ -2405,7 +2410,7 @@ MHD_parse_arguments_ (struct MHD_Connection *connection,
                       enum MHD_ValueKind kind,
                       char *args,
                       MHD_ArgumentIterator_ cb,
-                      unsigned int *num_headers);
+                      void *cls);
 
 
 /**
diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h
index 3d56ba35..9e3a0334 100644
--- a/src/microhttpd/mhd_str.h
+++ b/src/microhttpd/mhd_str.h
@@ -72,6 +72,15 @@ struct _MHD_str_w_len
   size_t len;
 };
 
+/**
+ * Modifiable string with length
+ */
+struct _MHD_mstr_w_len
+{
+  char *str;
+  size_t len;
+};
+
 /**
  * Static string initialiser for struct _MHD_str_w_len
  */
@@ -489,7 +498,7 @@ MHD_bin_to_hex (const void *bin,
  * 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
+ * Null-termination for input strings is not required, binary zeros compared
  * like other characters.
  *
  * @param quoted the quoted string to compare, must NOT include leading and
@@ -515,7 +524,7 @@ MHD_str_equal_quoted_bin_n (const char *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
+ * Null-termination for input strings is not required, binary zeros compared
  * like other characters.
  *
  * @param quoted the quoted string to compare, must NOT include leading and
diff --git a/src/testcurl/test_digestauth.c b/src/testcurl/test_digestauth.c
index 6f22c1f2..872eebc4 100644
--- a/src/testcurl/test_digestauth.c
+++ b/src/testcurl/test_digestauth.c
@@ -216,7 +216,7 @@ _checkCURLE_OK_func (CURLcode code, const char *curlFunc,
 /* Could be increased to facilitate debugging */
 #define TIMEOUTS_VAL 5
 
-#define MHD_URI_BASE_PATH "/bar%20foo%3Fkey%3Dvalue"
+#define MHD_URI_BASE_PATH "/bar%20foo?key=value"
 
 #define PAGE \
   "<html><head><title>libmicrohttpd demo</title></head><body>Access 
granted</body></html>"
diff --git a/src/testcurl/test_digestauth_with_arguments.c 
b/src/testcurl/test_digestauth_with_arguments.c
index 843e4684..631169e8 100644
--- a/src/testcurl/test_digestauth_with_arguments.c
+++ b/src/testcurl/test_digestauth_with_arguments.c
@@ -234,7 +234,8 @@ testDigestAuth ()
   }
   snprintf (url,
             sizeof (url),
-            "http://127.0.0.1:%d/bar%%20foo%%3Fkey%%3Dvalue";,
+            "http://127.0.0.1:%d/bar%%20foo?";
+            "key=value&more=even%%20more&empty&=no_key&&same=one&&same=two",
             port);
   c = curl_easy_init ();
   curl_easy_setopt (c, CURLOPT_URL, url);

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