]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
http: clear the proxy credentials as well on port or scheme change
authorDaniel Stenberg <daniel@haxx.se>
Mon, 13 Apr 2026 15:17:23 +0000 (17:17 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 14 Apr 2026 14:14:51 +0000 (16:14 +0200)
Add tests 2009-2011 to verify switching between proxies with credentials
when the switch is driven by a redirect

Reported-by: Dwij Mehta
Closes #21304

lib/http.c
lib/transfer.c
lib/transfer.h
tests/data/Makefile.am
tests/data/test2009 [new file with mode: 0644]
tests/data/test2010 [new file with mode: 0644]
tests/data/test2011 [new file with mode: 0644]

index a1e58e886c99ed4995988aceaffd16211386f83f..f976987111b7177937717bdc98dbd30d3a169b37 100644 (file)
@@ -1278,12 +1278,24 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
         curlx_free(scheme);
       }
       if(clear) {
+        CURLcode result = Curl_reset_userpwd(data);
+        if(result) {
+          curlx_free(follow_url);
+          return result;
+        }
         curlx_safefree(data->state.aptr.user);
         curlx_safefree(data->state.aptr.passwd);
       }
     }
   }
   DEBUGASSERT(follow_url);
+  {
+    CURLcode result = Curl_reset_proxypwd(data);
+    if(result) {
+      curlx_free(follow_url);
+      return result;
+    }
+  }
 
   if(type == FOLLOW_FAKE) {
     /* we are only figuring out the new URL if we would have followed locations
index dd4e16b7f5a366f8f96318cb2fe5847293b77e2d..a2fce9331bcbf09a1280a00c17964c807ef1d534 100644 (file)
@@ -438,6 +438,40 @@ void Curl_init_CONNECT(struct Curl_easy *data)
   data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
 }
 
+/*
+ * Restore the user credentials to those set in options.
+ */
+CURLcode Curl_reset_userpwd(struct Curl_easy *data)
+{
+  CURLcode result;
+  if(data->set.str[STRING_USERNAME] || data->set.str[STRING_PASSWORD])
+    data->state.creds_from = CREDS_OPTION;
+  result = Curl_setstropt(&data->state.aptr.user,
+                          data->set.str[STRING_USERNAME]);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.passwd,
+                            data->set.str[STRING_PASSWORD]);
+  return result;
+}
+
+/*
+ * Restore the proxy credentials to those set in options.
+ */
+CURLcode Curl_reset_proxypwd(struct Curl_easy *data)
+{
+#ifndef CURL_DISABLE_PROXY
+  CURLcode result = Curl_setstropt(&data->state.aptr.proxyuser,
+                                   data->set.str[STRING_PROXYUSERNAME]);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.proxypasswd,
+                            data->set.str[STRING_PROXYPASSWORD]);
+  return result;
+#else
+  (void)data;
+  return CURLE_OK;
+#endif
+}
+
 /*
  * Curl_pretransfer() is called immediately before a transfer starts, and only
  * once for one transfer no matter if it has redirects or do multi-pass
@@ -586,23 +620,10 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
       return CURLE_OUT_OF_MEMORY;
   }
 
-  if(data->set.str[STRING_USERNAME] ||
-     data->set.str[STRING_PASSWORD])
-    data->state.creds_from = CREDS_OPTION;
   if(!result)
-    result = Curl_setstropt(&data->state.aptr.user,
-                            data->set.str[STRING_USERNAME]);
+    result = Curl_reset_userpwd(data);
   if(!result)
-    result = Curl_setstropt(&data->state.aptr.passwd,
-                            data->set.str[STRING_PASSWORD]);
-#ifndef CURL_DISABLE_PROXY
-  if(!result)
-    result = Curl_setstropt(&data->state.aptr.proxyuser,
-                            data->set.str[STRING_PROXYUSERNAME]);
-  if(!result)
-    result = Curl_setstropt(&data->state.aptr.proxypasswd,
-                            data->set.str[STRING_PROXYPASSWORD]);
-#endif
+    result = Curl_reset_proxypwd(data);
 
   data->req.headerbytecount = 0;
   Curl_headers_cleanup(data);
index 41ec0357f681be5f4f1382ca3d7fa9a32c745acb..b29e70b9ec12750531f1919cebfc01605b1de787 100644 (file)
@@ -31,6 +31,8 @@ char *Curl_checkheaders(const struct Curl_easy *data,
 
 void Curl_init_CONNECT(struct Curl_easy *data);
 
+CURLcode Curl_reset_userpwd(struct Curl_easy *data);
+CURLcode Curl_reset_proxypwd(struct Curl_easy *data);
 CURLcode Curl_pretransfer(struct Curl_easy *data);
 
 CURLcode Curl_sendrecv(struct Curl_easy *data);
index 44ff75668f4c3071c668119b0cbd4a26c7d56755..3003dce03b0dd97a21646acc7d1e84dfb3a1aae2 100644 (file)
@@ -244,7 +244,7 @@ test1970 test1971 test1972 test1973 test1974 test1975 test1976 test1977 \
 test1978 test1979 test1980 test1981 test1982 test1983 test1984 \
 \
 test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \
-test2008 \
+test2008 test2009 test2010 test2011 \
 \
                                                                test2023 \
 test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \
diff --git a/tests/data/test2009 b/tests/data/test2009
new file mode 100644 (file)
index 0000000..d2fd79e
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP proxy
+http_proxy
+</keywords>
+</info>
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 407 Denied
+
+</connect>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 301 redirect
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 4
+Content-Type: text/html
+Location: https://another.example/%TESTNUMBER0002
+
+boo
+</data>
+</reply>
+
+# Client-side
+<client>
+<features>
+proxy
+</features>
+<server>
+http
+https
+</server>
+<name>
+proxy credentials via env variables, redirect from http to https
+</name>
+
+<setenv>
+http_proxy=http://user:secret@%HOSTIP:%HTTPPORT
+https_proxy=https://%HOSTIP:%HTTPSPORT/
+</setenv>
+<command>
+http://somewhere.example/ --follow --proxy-insecure
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="headers">
+GET http://somewhere.example/ HTTP/1.1
+Host: somewhere.example
+Proxy-Authorization: Basic %b64[user:secret]b64%
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+CONNECT another.example:443 HTTP/1.1
+Host: another.example:443
+User-Agent: curl/%VERSION
+Proxy-Connection: Keep-Alive
+
+</protocol>
+<errorcode>
+7
+</errorcode>
+</verify>
+</testcase>
diff --git a/tests/data/test2010 b/tests/data/test2010
new file mode 100644 (file)
index 0000000..443ae9d
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP proxy
+http_proxy
+</keywords>
+</info>
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 407 Denied
+
+</connect>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 301 redirect
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 4
+Content-Type: text/html
+Location: https://another.example/%TESTNUMBER0002
+
+boo
+</data>
+</reply>
+
+# Client-side
+<client>
+<features>
+proxy
+</features>
+<server>
+http
+https
+</server>
+<name>
+proxy credentials via options for two proxies, redirect from http to https
+</name>
+
+<setenv>
+http_proxy=http://%HOSTIP:%HTTPPORT
+https_proxy=https://%HOSTIP:%HTTPSPORT/
+</setenv>
+<command>
+--proxy-user batman:robin http://somewhere.example/ --follow --proxy-insecure
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="headers">
+GET http://somewhere.example/ HTTP/1.1
+Host: somewhere.example
+Proxy-Authorization: Basic %b64[batman:robin]b64%
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+CONNECT another.example:443 HTTP/1.1
+Host: another.example:443
+Proxy-Authorization: Basic %b64[batman:robin]b64%
+User-Agent: curl/%VERSION
+Proxy-Connection: Keep-Alive
+
+</protocol>
+<errorcode>
+7
+</errorcode>
+</verify>
+</testcase>
diff --git a/tests/data/test2011 b/tests/data/test2011
new file mode 100644 (file)
index 0000000..dd4e534
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP proxy
+http_proxy
+</keywords>
+</info>
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 407 Denied
+
+</connect>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 301 redirect
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 4
+Content-Type: text/html
+Location: https://another.example/%TESTNUMBER0002
+
+boo
+</data>
+</reply>
+
+# Client-side
+<client>
+<features>
+proxy
+</features>
+<server>
+http
+https
+</server>
+<name>
+proxy creds via env, cross-scheme redirect, --location-trusted
+</name>
+
+<setenv>
+http_proxy=http://user:secret@%HOSTIP:%HTTPPORT
+https_proxy=https://%HOSTIP:%HTTPSPORT/
+</setenv>
+<command>
+http://somewhere.example/ --location-trusted --proxy-insecure
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="headers">
+GET http://somewhere.example/ HTTP/1.1
+Host: somewhere.example
+Proxy-Authorization: Basic %b64[user:secret]b64%
+User-Agent: curl/%VERSION
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+CONNECT another.example:443 HTTP/1.1
+Host: another.example:443
+User-Agent: curl/%VERSION
+Proxy-Connection: Keep-Alive
+
+</protocol>
+<errorcode>
+7
+</errorcode>
+</verify>
+</testcase>