+/* With auth lock taken */
+static gboolean
+update_digest_cb (gchar *key, GstRTSPDigestEntry *entry, GHashTable *digest)
+{
+ g_hash_table_replace (digest, key, entry);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtsp_auth_parse_htdigest:
+ * @path: (type filename): Path to the htdigest file
+ * @token: (transfer none): authorisation token
+ *
+ * Parse the contents of the file at @path and enable the privileges
+ * listed in @token for the users it describes.
+ *
+ * The format of the file is expected to match the format described by
+ * <https://en.wikipedia.org/wiki/Digest_access_authentication#The_.htdigest_file>,
+ * as output by the `htdigest` command.
+ *
+ * Returns: %TRUE if the file was successfully parsed, %FALSE otherwise.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtsp_auth_parse_htdigest (GstRTSPAuth *auth, const gchar *path,
+ GstRTSPToken *token)
+{
+ GstRTSPAuthPrivate *priv;
+ gboolean ret = FALSE;
+ gchar *line = NULL;
+ gchar *eol = NULL;
+ gchar *contents = NULL;
+ GError *error = NULL;
+ GHashTable *new_entries = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) gst_rtsp_digest_entry_free);
+
+
+ g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_RTSP_TOKEN (token), FALSE);
+
+ priv = auth->priv;
+ if (!g_file_get_contents (path, &contents, NULL, &error)) {
+ GST_ERROR_OBJECT(auth, "Could not parse htdigest: %s", error->message);
+ goto done;
+ }
+
+ for (line = contents; line && *line; line = eol ? eol + 1 : NULL) {
+ GstRTSPDigestEntry *entry;
+ gchar **strv;
+ eol = strchr (line, '\n');
+
+ if (eol)
+ *eol = '\0';
+
+ strv = g_strsplit (line, ":", -1);
+
+ if (!(strv[0] && strv[1] && strv[2] && !strv[3])) {
+ GST_ERROR_OBJECT (auth, "Invalid htdigest format");
+ g_strfreev (strv);
+ goto done;
+ }
+
+ if (strlen (strv[2]) != 32) {
+ GST_ERROR_OBJECT (auth, "Invalid htdigest format, hash is expected to be 32 characters long");
+ g_strfreev (strv);
+ goto done;
+ }
+
+ entry = g_new0 (GstRTSPDigestEntry, 1);
+ entry->token = gst_rtsp_token_ref (token);
+ entry->md5_pass = g_strdup (strv[2]);
+ g_hash_table_replace (new_entries, g_strdup (strv[0]), entry);
+ g_strfreev (strv);
+ }
+
+ ret = TRUE;
+
+ /* We only update digest if the file was entirely valid */
+ g_mutex_lock (&priv->lock);
+ g_hash_table_foreach_steal (new_entries, (GHRFunc) update_digest_cb, priv->digest);
+ g_mutex_unlock (&priv->lock);
+
+done:
+ if (error)
+ g_clear_error (&error);
+ g_free(contents);
+ g_hash_table_unref (new_entries);
+ return ret;
+}
+