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