diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go index 24ef18a41..9fa56dfad 100644 --- a/weed/s3api/auth_signature_v4.go +++ b/weed/s3api/auth_signature_v4.go @@ -604,68 +604,42 @@ func extractHostHeader(r *http.Request) string { scheme = "http" } - // If X-Forwarded-Host is set, use that as the host. - // If X-Forwarded-Port is set, use that too to form the host. - // If X-Forwarded-Proto is set, check if it is default to omit the port. + var host, port string if forwardedHost != "" { - extractedHost := forwardedHost - host, port, err := net.SplitHostPort(extractedHost) - hostHadPort := (err == nil) - - if hostHadPort { - // forwardedHost contained a port (e.g., "example.com:8080" or "[::1]:8080") - extractedHost = host - if forwardedPort == "" { - forwardedPort = port - } - - if !isDefaultPort(scheme, forwardedPort) { - extractedHost = net.JoinHostPort(extractedHost, forwardedPort) - } else { - // No port to add, but IPv6 addresses need brackets for canonical host header - if strings.Contains(extractedHost, ":") && !strings.HasPrefix(extractedHost, "[") { - extractedHost = "[" + extractedHost + "]" - } - } - } else { - // forwardedHost did not contain a port (e.g., "example.com" or "::1" or "[::1]") - // Use forwardedPort if provided and non-default - if forwardedPort != "" && !isDefaultPort(scheme, forwardedPort) { - // Strip brackets from IPv6 before JoinHostPort (it will add them back) - if strings.HasPrefix(extractedHost, "[") && strings.HasSuffix(extractedHost, "]") { - extractedHost = extractedHost[1 : len(extractedHost)-1] - } - extractedHost = net.JoinHostPort(extractedHost, forwardedPort) - } else { - // No port to add, but IPv6 addresses need brackets - if strings.Contains(extractedHost, ":") && !strings.HasPrefix(extractedHost, "[") { - extractedHost = "[" + extractedHost + "]" - } + host = forwardedHost + port = forwardedPort + if h, p, err := net.SplitHostPort(host); err == nil { + host = h + if port == "" { + port = p } } - return extractedHost } else { - // Go http server removes "host" from Request.Header - host := r.Host + host = r.Host if host == "" { host = r.URL.Host } - h, port, err := net.SplitHostPort(host) - if err != nil { - // Handle bare IPv6 address without port - if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { - return "[" + host + "]" - } - return host + if h, p, err := net.SplitHostPort(host); err == nil { + host = h + port = p } - if isDefaultPort(scheme, port) { - if strings.Contains(h, ":") { // is IPv6 - return "[" + h + "]" - } - return h + } + + // If we have a non-default port, join it with the host. + // net.JoinHostPort will handle bracketing for IPv6. + if port != "" && !isDefaultPort(scheme, port) { + // Before joining, strip brackets from host if they exist, as JoinHostPort adds them. + if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { + host = host[1 : len(host)-1] } - return host + return net.JoinHostPort(host, port) + } + + // No port or default port, just ensure host is correctly formatted (IPv6 brackets). + if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { + return "[" + host + "]" } + return host } func isDefaultPort(scheme, port string) bool { diff --git a/weed/s3api/auto_signature_v4_test.go b/weed/s3api/auto_signature_v4_test.go index ba1bf25ce..473fe3e88 100644 --- a/weed/s3api/auto_signature_v4_test.go +++ b/weed/s3api/auto_signature_v4_test.go @@ -608,7 +608,7 @@ func TestSignatureV4WithForwardedPort(t *testing.T) { forwardedHost: "[::1]:443", forwardedPort: "443", forwardedProto: "https", - expectedHost: "::1", + expectedHost: "[::1]", }, { name: "IPv6 X-Forwarded-Host with standard http port already included (Traefik/HAProxy style)", @@ -616,7 +616,7 @@ func TestSignatureV4WithForwardedPort(t *testing.T) { forwardedHost: "[::1]:80", forwardedPort: "80", forwardedProto: "http", - expectedHost: "::1", + expectedHost: "[::1]", }, { name: "IPv6 with port in brackets",