Skip to content

Commit 02fa6c3

Browse files
fix(files): honor forwarded HTTPS proxy chains
1 parent 2048229 commit 02fa6c3

2 files changed

Lines changed: 27 additions & 1 deletion

File tree

internal/files/web.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ func (h *webSrv) clear(w http.ResponseWriter, r *http.Request) {
115115
}
116116

117117
func secureReq(r *http.Request) bool {
118-
return r.TLS != nil || strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https")
118+
if r.TLS != nil {
119+
return true
120+
}
121+
proto, _, _ := strings.Cut(r.Header.Get("X-Forwarded-Proto"), ",")
122+
return strings.EqualFold(strings.TrimSpace(proto), "https")
119123
}
120124

121125
func randHex(n int) string {

internal/files/web_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,28 @@ func TestWebRequiresAuth(t *testing.T) {
6161
}
6262
}
6363

64+
func TestSecureReqUsesFirstForwardedProto(t *testing.T) {
65+
for _, tc := range []struct {
66+
name string
67+
proto string
68+
secure bool
69+
}{
70+
{name: "https", proto: "https", secure: true},
71+
{name: "proxy chain", proto: "https, http", secure: true},
72+
{name: "case and whitespace", proto: " HTTPS , http", secure: true},
73+
{name: "http", proto: "http", secure: false},
74+
{name: "untrusted later value", proto: "http, https", secure: false},
75+
} {
76+
t.Run(tc.name, func(t *testing.T) {
77+
req := httptest.NewRequest(http.MethodGet, "/", nil)
78+
req.Header.Set("X-Forwarded-Proto", tc.proto)
79+
if got := secureReq(req); got != tc.secure {
80+
t.Fatalf("secureReq() = %v, want %v for %q", got, tc.secure, tc.proto)
81+
}
82+
})
83+
}
84+
}
85+
6486
func TestWebRoundTrip(t *testing.T) {
6587
h, _ := webTestHandler(t)
6688

0 commit comments

Comments
 (0)