diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go index 0d9f2fd16..f15bac4a9 100644 --- a/weed/s3api/auth_signature_v4.go +++ b/weed/s3api/auth_signature_v4.go @@ -595,24 +595,23 @@ func extractHostHeader(r *http.Request) string { if forwardedHost := r.Header.Get("X-Forwarded-Host"); forwardedHost != "" { // Check if X-Forwarded-Host already contains a port // This handles proxies (like Traefik, HAProxy) that include port in X-Forwarded-Host - _, _, err := net.SplitHostPort(forwardedHost) - if err == nil { + if _, _, err := net.SplitHostPort(forwardedHost); err == nil { // X-Forwarded-Host already contains a port (e.g., "example.com:8443" or "[::1]:8080") // Use it as-is return forwardedHost } + // An IPv6 address literal must be enclosed in square brackets. + if strings.Contains(forwardedHost, ":") && !strings.HasPrefix(forwardedHost, "[") { + forwardedHost = "[" + forwardedHost + "]" + } + // X-Forwarded-Host doesn't contain a port, check if X-Forwarded-Port is provided if forwardedPort := r.Header.Get("X-Forwarded-Port"); forwardedPort != "" { // Determine the protocol to check for standard ports proto := strings.ToLower(r.Header.Get("X-Forwarded-Proto")) // Only add port if it's not the standard port for the protocol if (proto == "https" && forwardedPort != "443") || (proto != "https" && forwardedPort != "80") { - // Handle IPv6 addresses: wrap in brackets if needed - if strings.Contains(forwardedHost, ":") && !strings.HasPrefix(forwardedHost, "[") { - // This is an IPv6 address without brackets - return "[" + forwardedHost + "]:" + forwardedPort - } return forwardedHost + ":" + forwardedPort } } diff --git a/weed/s3api/auth_signature_v4_test.go b/weed/s3api/auth_signature_v4_test.go index 834d1c68c..3215ba9ba 100644 --- a/weed/s3api/auth_signature_v4_test.go +++ b/weed/s3api/auth_signature_v4_test.go @@ -191,6 +191,22 @@ func TestExtractHostHeader(t *testing.T) { forwardedProto: "http", expected: "[::1]:8080", }, + { + name: "IPv6 address without brackets and standard port, should return bracketed IPv6", + hostHeader: "backend:8333", + forwardedHost: "::1", + forwardedPort: "80", + forwardedProto: "http", + expected: "[::1]", + }, + { + name: "IPv6 address without brackets and standard HTTPS port, should return bracketed IPv6", + hostHeader: "backend:8333", + forwardedHost: "2001:db8::1", + forwardedPort: "443", + forwardedProto: "https", + expected: "[2001:db8::1]", + }, { name: "IPv6 address with brackets but no port, should add port", hostHeader: "backend:8333",