@@ -1530,6 +1530,55 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
1530
1530
}
1531
1531
}
1532
1532
1533
+ // Issue #70530: Once we strip a header on a redirect to a different host,
1534
+ // the header should stay stripped across any further redirects.
1535
+ func TestClientStripHeadersOnRepeatedRedirect (t * testing.T ) {
1536
+ run (t , testClientStripHeadersOnRepeatedRedirect )
1537
+ }
1538
+ func testClientStripHeadersOnRepeatedRedirect (t * testing.T , mode testMode ) {
1539
+ var proto string
1540
+ ts := newClientServerTest (t , mode , HandlerFunc (func (w ResponseWriter , r * Request ) {
1541
+ if r .Host + r .URL .Path != "a.example.com/" {
1542
+ if h := r .Header .Get ("Authorization" ); h != "" {
1543
+ t .Errorf ("on request to %v%v, Authorization=%q, want no header" , r .Host , r .URL .Path , h )
1544
+ }
1545
+ }
1546
+ // Follow a chain of redirects from a to b and back to a.
1547
+ // The Authorization header is stripped on the first redirect to b,
1548
+ // and stays stripped even if we're sent back to a.
1549
+ switch r .Host + r .URL .Path {
1550
+ case "a.example.com/" :
1551
+ Redirect (w , r , proto + "://b.example.com/" , StatusFound )
1552
+ case "b.example.com/" :
1553
+ Redirect (w , r , proto + "://b.example.com/redirect" , StatusFound )
1554
+ case "b.example.com/redirect" :
1555
+ Redirect (w , r , proto + "://a.example.com/redirect" , StatusFound )
1556
+ case "a.example.com/redirect" :
1557
+ w .Header ().Set ("X-Done" , "true" )
1558
+ default :
1559
+ t .Errorf ("unexpected request to %v" , r .URL )
1560
+ }
1561
+ })).ts
1562
+ proto , _ , _ = strings .Cut (ts .URL , ":" )
1563
+
1564
+ c := ts .Client ()
1565
+ c .Transport .(* Transport ).Dial = func (_ string , _ string ) (net.Conn , error ) {
1566
+ return net .Dial ("tcp" , ts .Listener .Addr ().String ())
1567
+ }
1568
+
1569
+ req , _ := NewRequest ("GET" , proto + "://a.example.com/" , nil )
1570
+ req .Header .Add ("Cookie" , "foo=bar" )
1571
+ req .Header .Add ("Authorization" , "secretpassword" )
1572
+ res , err := c .Do (req )
1573
+ if err != nil {
1574
+ t .Fatal (err )
1575
+ }
1576
+ defer res .Body .Close ()
1577
+ if res .Header .Get ("X-Done" ) != "true" {
1578
+ t .Fatalf ("response missing expected header: X-Done=true" )
1579
+ }
1580
+ }
1581
+
1533
1582
// Issue 22233: copy host when Client follows a relative redirect.
1534
1583
func TestClientCopyHostOnRedirect (t * testing.T ) { run (t , testClientCopyHostOnRedirect ) }
1535
1584
func testClientCopyHostOnRedirect (t * testing.T , mode testMode ) {
@@ -1696,43 +1745,39 @@ func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) {
1696
1745
// Part of Issue 4800
1697
1746
func TestShouldCopyHeaderOnRedirect (t * testing.T ) {
1698
1747
tests := []struct {
1699
- header string
1700
1748
initialURL string
1701
1749
destURL string
1702
1750
want bool
1703
1751
}{
1704
- {"User-Agent" , "http://foo.com/" , "http://bar.com/" , true },
1705
- {"X-Foo" , "http://foo.com/" , "http://bar.com/" , true },
1706
-
1707
1752
// Sensitive headers:
1708
- {"cookie" , " http://foo.com/" , "http://bar.com/" , false },
1709
- {"cookie2" , " http://foo.com/" , "http://bar.com/" , false },
1710
- {"authorization" , " http://foo.com/" , "http://bar.com/" , false },
1711
- {"authorization" , " http://foo.com/" , "https://foo.com/" , true },
1712
- {"authorization" , " http://foo.com:1234/" , "http://foo.com:4321/" , true },
1713
- {"www-authenticate" , " http://foo.com/" , "http://bar.com/" , false },
1714
- {"authorization" , " http://foo.com/" , "http://[::1%25.foo.com]/" , false },
1753
+ {"http://foo.com/" , "http://bar.com/" , false },
1754
+ {"http://foo.com/" , "http://bar.com/" , false },
1755
+ {"http://foo.com/" , "http://bar.com/" , false },
1756
+ {"http://foo.com/" , "https://foo.com/" , true },
1757
+ {"http://foo.com:1234/" , "http://foo.com:4321/" , true },
1758
+ {"http://foo.com/" , "http://bar.com/" , false },
1759
+ {"http://foo.com/" , "http://[::1%25.foo.com]/" , false },
1715
1760
1716
1761
// But subdomains should work:
1717
- {"www-authenticate" , " http://foo.com/" , "http://foo.com/" , true },
1718
- {"www-authenticate" , " http://foo.com/" , "http://sub.foo.com/" , true },
1719
- {"www-authenticate" , " http://foo.com/" , "http://notfoo.com/" , false },
1720
- {"www-authenticate" , " http://foo.com/" , "https://foo.com/" , true },
1721
- {"www-authenticate" , " http://foo.com:80/" , "http://foo.com/" , true },
1722
- {"www-authenticate" , " http://foo.com:80/" , "http://sub.foo.com/" , true },
1723
- {"www-authenticate" , " http://foo.com:443/" , "https://foo.com/" , true },
1724
- {"www-authenticate" , " http://foo.com:443/" , "https://sub.foo.com/" , true },
1725
- {"www-authenticate" , " http://foo.com:1234/" , "http://foo.com/" , true },
1726
-
1727
- {"authorization" , " http://foo.com/" , "http://foo.com/" , true },
1728
- {"authorization" , " http://foo.com/" , "http://sub.foo.com/" , true },
1729
- {"authorization" , " http://foo.com/" , "http://notfoo.com/" , false },
1730
- {"authorization" , " http://foo.com/" , "https://foo.com/" , true },
1731
- {"authorization" , " http://foo.com:80/" , "http://foo.com/" , true },
1732
- {"authorization" , " http://foo.com:80/" , "http://sub.foo.com/" , true },
1733
- {"authorization" , " http://foo.com:443/" , "https://foo.com/" , true },
1734
- {"authorization" , " http://foo.com:443/" , "https://sub.foo.com/" , true },
1735
- {"authorization" , " http://foo.com:1234/" , "http://foo.com/" , true },
1762
+ {"http://foo.com/" , "http://foo.com/" , true },
1763
+ {"http://foo.com/" , "http://sub.foo.com/" , true },
1764
+ {"http://foo.com/" , "http://notfoo.com/" , false },
1765
+ {"http://foo.com/" , "https://foo.com/" , true },
1766
+ {"http://foo.com:80/" , "http://foo.com/" , true },
1767
+ {"http://foo.com:80/" , "http://sub.foo.com/" , true },
1768
+ {"http://foo.com:443/" , "https://foo.com/" , true },
1769
+ {"http://foo.com:443/" , "https://sub.foo.com/" , true },
1770
+ {"http://foo.com:1234/" , "http://foo.com/" , true },
1771
+
1772
+ {"http://foo.com/" , "http://foo.com/" , true },
1773
+ {"http://foo.com/" , "http://sub.foo.com/" , true },
1774
+ {"http://foo.com/" , "http://notfoo.com/" , false },
1775
+ {"http://foo.com/" , "https://foo.com/" , true },
1776
+ {"http://foo.com:80/" , "http://foo.com/" , true },
1777
+ {"http://foo.com:80/" , "http://sub.foo.com/" , true },
1778
+ {"http://foo.com:443/" , "https://foo.com/" , true },
1779
+ {"http://foo.com:443/" , "https://sub.foo.com/" , true },
1780
+ {"http://foo.com:1234/" , "http://foo.com/" , true },
1736
1781
}
1737
1782
for i , tt := range tests {
1738
1783
u0 , err := url .Parse (tt .initialURL )
@@ -1745,10 +1790,10 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
1745
1790
t .Errorf ("%d. dest URL %q parse error: %v" , i , tt .destURL , err )
1746
1791
continue
1747
1792
}
1748
- got := Export_shouldCopyHeaderOnRedirect (tt . header , u0 , u1 )
1793
+ got := Export_shouldCopyHeaderOnRedirect (u0 , u1 )
1749
1794
if got != tt .want {
1750
- t .Errorf ("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v" ,
1751
- i , tt .header , tt . initialURL , tt .destURL , got , tt .want )
1795
+ t .Errorf ("%d. shouldCopyHeaderOnRedirect(%q => %q) = %v; want %v" ,
1796
+ i , tt .initialURL , tt .destURL , got , tt .want )
1752
1797
}
1753
1798
}
1754
1799
}
0 commit comments