diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go index 05805f2ad..963cf12a0 100644 --- a/weed/s3api/auth_signature_v4.go +++ b/weed/s3api/auth_signature_v4.go @@ -769,7 +769,7 @@ func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header, extractedSignedHeaders := make(http.Header) for _, header := range signedHeaders { // `host` is not a case-sensitive header, unlike other headers such as `x-amz-date`. - if header == "host" { + if strings.ToLower(header) == "host" { // Get host value. hostHeaderValue := extractHostHeader(r) extractedSignedHeaders[header] = []string{hostHeaderValue} @@ -815,12 +815,12 @@ func extractHostHeader(r *http.Request) string { } else { host = strings.TrimSpace(forwardedHost) } - port = forwardedPort if h, p, err := net.SplitHostPort(host); err == nil { host = h - if port == "" { - port = p - } + port = p + } + if forwardedPort != "" && isDefaultPort(scheme, port) { + port = forwardedPort } } else { host = r.Host diff --git a/weed/s3api/auth_signature_v4_test.go b/weed/s3api/auth_signature_v4_test.go index 849d895b5..782ce6a5b 100644 --- a/weed/s3api/auth_signature_v4_test.go +++ b/weed/s3api/auth_signature_v4_test.go @@ -292,6 +292,47 @@ func TestExtractHostHeader(t *testing.T) { forwardedProto: "http", expected: "[::ffff:127.0.0.1]:8080", }, + { + name: "Simple port 442", + hostHeader: "bucket.domain.com:442", + expected: "bucket.domain.com:442", + }, + { + name: "Port 442 with X-Forwarded-Host", + hostHeader: "backend:8333", + forwardedHost: "bucket.domain.com:442", + expected: "bucket.domain.com:442", + }, + { + name: "Port 442 with X-Forwarded-Port", + hostHeader: "backend:8333", + forwardedHost: "bucket.domain.com", + forwardedPort: "442", + expected: "bucket.domain.com:442", + }, + { + name: "HTTPS with port 442 (should NOT strip)", + hostHeader: "bucket.domain.com:442", + forwardedProto: "https", + expected: "bucket.domain.com:442", + }, + { + name: "X-Forwarded-Host with multiple hosts (including port)", + forwardedHost: "bucket.domain.com:442, internal.proxy", + expected: "bucket.domain.com:442", + }, + { + name: "IPv6 with port", + hostHeader: "[2001:db8::1]:442", + expected: "[2001:db8::1]:442", + }, + { + name: "X-Forwarded-Host with port 442, but X-Forwarded-Port is 80 (should PREFER 442)", + forwardedHost: "bucket.domain.com:442", + forwardedPort: "80", + forwardedProto: "http", + expected: "bucket.domain.com:442", + }, } for _, tt := range tests { @@ -322,3 +363,40 @@ func TestExtractHostHeader(t *testing.T) { }) } } + +func TestExtractSignedHeadersCase(t *testing.T) { + tests := []struct { + name string + host string + signedHeads []string + expected string + }{ + { + name: "lowercase host", + host: "bucket.domain.com:442", + signedHeads: []string{"host"}, + expected: "host:bucket.domain.com:442\n", + }, + { + name: "uppercase Host", + host: "bucket.domain.com:442", + signedHeads: []string{"Host"}, + expected: "host:bucket.domain.com:442\n", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r, _ := http.NewRequest("GET", "http://"+tt.host+"/", nil) + r.Host = tt.host + extracted, errCode := extractSignedHeaders(tt.signedHeads, r) + if errCode != s3err.ErrNone { + t.Fatalf("extractSignedHeaders failed: %v", errCode) + } + actual := getCanonicalHeaders(extracted) + if actual != tt.expected { + t.Errorf("%s: expected %q, got %q", tt.name, tt.expected, actual) + } + }) + } +}