Signed-off-by: Zhigong Liu <[email protected]>
---
 libavformat/httpauth.c | 83 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 68 insertions(+), 15 deletions(-)

diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c
index 9048362509..5260b4a9a4 100644
--- a/libavformat/httpauth.c
+++ b/libavformat/httpauth.c
@@ -92,25 +92,57 @@ void ff_http_auth_handle_header(HTTPAuthState *state, const 
char *key,
 {
     if (!av_strcasecmp(key, "WWW-Authenticate") || !av_strcasecmp(key, 
"Proxy-Authenticate")) {
         const char *p;
+        av_log(NULL, AV_LOG_DEBUG, "Processing auth header: %s: %s\n", key, 
value);
+        
         if (av_stristart(value, "Basic ", &p) &&
             state->auth_type <= HTTP_AUTH_BASIC) {
+            av_log(NULL, AV_LOG_DEBUG, "Setting Basic authentication\n");
             state->auth_type = HTTP_AUTH_BASIC;
             state->realm[0] = 0;
             state->stale = 0;
             ff_parse_key_value(p, (ff_parse_key_val_cb) handle_basic_params,
                                state);
-        } else if (av_stristart(value, "Digest ", &p) &&
-                   state->auth_type <= HTTP_AUTH_DIGEST) {
-            state->auth_type = HTTP_AUTH_DIGEST;
-            memset(&state->digest_params, 0, sizeof(DigestParams));
-            state->realm[0] = 0;
-            state->stale = 0;
-            ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params,
-                               state);
-            choose_qop(state->digest_params.qop,
-                       sizeof(state->digest_params.qop));
-            if (!av_strcasecmp(state->digest_params.stale, "true"))
-                state->stale = 1;
+        } else if (av_stristart(value, "Digest ", &p)) {
+            /* Handle multiple Digest authentication headers by preferring MD5 
over SHA-256
+             * or updating if we haven't set digest auth yet */
+            if (state->auth_type <= HTTP_AUTH_DIGEST) {
+                const char *alg_start = strstr(p, "algorithm=");
+                int is_md5 = 1; /* Default to MD5 if no algorithm specified */
+                
+                if (alg_start) {
+                    alg_start += 10; /* Skip "algorithm=" */
+                    if (av_strncasecmp(alg_start, "\"MD5\"", 5) == 0 || 
av_strncasecmp(alg_start, "MD5", 3) == 0) {
+                        is_md5 = 1;
+                    } else if (av_strncasecmp(alg_start, "\"SHA-256\"", 9) == 
0 || av_strncasecmp(alg_start, "SHA-256", 7) == 0) {
+                        is_md5 = 0;
+                    }
+                }
+                
+                av_log(NULL, AV_LOG_DEBUG, "Digest auth: algorithm=%s, 
is_md5=%d, current_auth_type=%d\n", 
+                       alg_start ? alg_start : "none", is_md5, 
state->auth_type);
+                
+                /* Prefer MD5 over SHA-256, or set if not already set */
+                if (state->auth_type < HTTP_AUTH_DIGEST || 
+                    (is_md5 && av_strcasecmp(state->digest_params.algorithm, 
"MD5") != 0)) {
+                    av_log(NULL, AV_LOG_DEBUG, "Setting Digest authentication 
with algorithm preference\n");
+                    state->auth_type = HTTP_AUTH_DIGEST;
+                    memset(&state->digest_params, 0, sizeof(DigestParams));
+                    state->realm[0] = 0;
+                    state->stale = 0;
+                    ff_parse_key_value(p, (ff_parse_key_val_cb) 
handle_digest_params,
+                                       state);
+                    choose_qop(state->digest_params.qop,
+                               sizeof(state->digest_params.qop));
+                    if (!av_strcasecmp(state->digest_params.stale, "true"))
+                        state->stale = 1;
+                    
+                    av_log(NULL, AV_LOG_DEBUG, "Digest params: realm=%s, 
nonce=%s, algorithm=%s, qop=%s\n",
+                           state->realm, state->digest_params.nonce, 
+                           state->digest_params.algorithm, 
state->digest_params.qop);
+                } else {
+                    av_log(NULL, AV_LOG_DEBUG, "Skipping digest auth header 
(already have better)\n");
+                }
+            }
         }
     } else if (!av_strcasecmp(key, "Authentication-Info")) {
         ff_parse_key_value(value, (ff_parse_key_val_cb) handle_digest_update,
@@ -220,9 +252,11 @@ static char *make_digest_auth(HTTPAuthState *state, const 
char *username,
     av_strlcatf(authstr, len, ", uri=\"%s\"",       uri);
     av_strlcatf(authstr, len, ", response=\"%s\"",  response);
 
-    // we are violating the RFC and use "" because all others seem to do that 
too.
+    // Always include algorithm for better compatibility
     if (digest->algorithm[0])
         av_strlcatf(authstr, len, ", algorithm=\"%s\"",  digest->algorithm);
+    else
+        av_strlcatf(authstr, len, ", algorithm=\"MD5\"");
 
     if (digest->opaque[0])
         av_strlcatf(authstr, len, ", opaque=\"%s\"", digest->opaque);
@@ -245,8 +279,14 @@ char *ff_http_auth_create_response(HTTPAuthState *state, 
const char *auth,
     /* Clear the stale flag, we assume the auth is ok now. It is reset
      * by the server headers if there's a new issue. */
     state->stale = 0;
-    if (!auth || !strchr(auth, ':'))
+    
+    av_log(NULL, AV_LOG_DEBUG, "Creating auth response: auth_type=%d, auth=%s, 
path=%s, method=%s\n",
+           state->auth_type, auth ? "[provided]" : "[null]", path ? path : 
"[null]", method ? method : "[null]");
+    
+    if (!auth || !strchr(auth, ':')) {
+        av_log(NULL, AV_LOG_DEBUG, "No valid auth credentials provided\n");
         return NULL;
+    }
 
     if (state->auth_type == HTTP_AUTH_BASIC) {
         int auth_b64_len, len;
@@ -269,17 +309,30 @@ char *ff_http_auth_create_response(HTTPAuthState *state, 
const char *auth,
         av_base64_encode(ptr, auth_b64_len, decoded_auth, 
strlen(decoded_auth));
         av_strlcat(ptr, "\r\n", len - (ptr - authstr));
         av_free(decoded_auth);
+        av_log(NULL, AV_LOG_DEBUG, "Created Basic auth response\n");
     } else if (state->auth_type == HTTP_AUTH_DIGEST) {
         char *username = ff_urldecode(auth, 0), *password;
 
-        if (!username)
+        if (!username) {
+            av_log(NULL, AV_LOG_DEBUG, "Failed to decode username\n");
             return NULL;
+        }
 
         if ((password = strchr(username, ':'))) {
             *password++ = 0;
+            av_log(NULL, AV_LOG_DEBUG, "Creating digest auth for user: %s\n", 
username);
             authstr = make_digest_auth(state, username, password, path, 
method);
+            if (authstr) {
+                av_log(NULL, AV_LOG_DEBUG, "Created Digest auth response: 
%s\n", authstr);
+            } else {
+                av_log(NULL, AV_LOG_DEBUG, "Failed to create Digest auth 
response\n");
+            }
+        } else {
+            av_log(NULL, AV_LOG_DEBUG, "No password found in auth string\n");
         }
         av_free(username);
+    } else {
+        av_log(NULL, AV_LOG_DEBUG, "Unknown auth type: %d\n", 
state->auth_type);
     }
     return authstr;
 }
-- 
2.49.0.windows.1

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to