diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go index 4d273de6a..b77540255 100644 --- a/weed/s3api/auth_signature_v4.go +++ b/weed/s3api/auth_signature_v4.go @@ -648,9 +648,14 @@ func extractHostHeader(r *http.Request) string { 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 + "]" + // No port or default port was stripped. According to AWS SDK behavior (aws-sdk-go-v2), + // when a default port is removed from an IPv6 address, the brackets should also be removed. + // This matches AWS S3 signature calculation requirements. + // Reference: https://github.com/aws/aws-sdk-go-v2/blob/main/aws/signer/internal/v4/host.go + // The stripPort function returns IPv6 without brackets when port is stripped. + if strings.Contains(host, ":") { + // This is an IPv6 address. Strip brackets to match AWS SDK behavior. + return strings.Trim(host, "[]") } return host } diff --git a/weed/s3api/auth_signature_v4_test.go b/weed/s3api/auth_signature_v4_test.go index 6850e9d2b..9ec4f232e 100644 --- a/weed/s3api/auth_signature_v4_test.go +++ b/weed/s3api/auth_signature_v4_test.go @@ -192,20 +192,20 @@ func TestExtractHostHeader(t *testing.T) { expected: "[::1]:8080", }, { - name: "IPv6 address without brackets and standard port, should return bracketed IPv6", + name: "IPv6 address without brackets and standard port, should strip brackets per AWS SDK", hostHeader: "backend:8333", forwardedHost: "::1", forwardedPort: "80", forwardedProto: "http", - expected: "[::1]", + expected: "::1", }, { - name: "IPv6 address without brackets and standard HTTPS port, should return bracketed IPv6", + name: "IPv6 address without brackets and standard HTTPS port, should strip brackets per AWS SDK", hostHeader: "backend:8333", forwardedHost: "2001:db8::1", forwardedPort: "443", forwardedProto: "https", - expected: "[2001:db8::1]", + expected: "2001:db8::1", }, { name: "IPv6 address with brackets but no port, should add port", @@ -216,12 +216,12 @@ func TestExtractHostHeader(t *testing.T) { expected: "[2001:db8::1]:8080", }, { - name: "IPv6 full address with brackets and default port (should strip port)", + name: "IPv6 full address with brackets and default port (should strip port and brackets)", hostHeader: "backend:8333", forwardedHost: "[2001:db8:85a3::8a2e:370:7334]:443", forwardedPort: "443", forwardedProto: "https", - expected: "[2001:db8:85a3::8a2e:370:7334]", + expected: "2001:db8:85a3::8a2e:370:7334", }, { name: "IPv4-mapped IPv6 address without brackets, should add brackets with port", diff --git a/weed/s3api/auto_signature_v4_test.go b/weed/s3api/auto_signature_v4_test.go index 6039081a1..47c55e077 100644 --- a/weed/s3api/auto_signature_v4_test.go +++ b/weed/s3api/auto_signature_v4_test.go @@ -451,25 +451,25 @@ func TestSignatureV4WithoutProxy(t *testing.T) { name: "IPv6 HTTP with standard port", host: "[::1]:80", proto: "http", - expectedHost: "[::1]", + expectedHost: "::1", }, { name: "IPv6 HTTPS with standard port", host: "[::1]:443", proto: "https", - expectedHost: "[::1]", + expectedHost: "::1", }, { name: "IPv6 HTTP without port", host: "::1", proto: "http", - expectedHost: "[::1]", + expectedHost: "::1", }, { name: "IPv6 HTTPS without port", host: "::1", proto: "https", - expectedHost: "[::1]", + expectedHost: "::1", }, } @@ -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",