aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/s3api_object_handlers_copy.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/s3api/s3api_object_handlers_copy.go')
-rw-r--r--weed/s3api/s3api_object_handlers_copy.go31
1 files changed, 29 insertions, 2 deletions
diff --git a/weed/s3api/s3api_object_handlers_copy.go b/weed/s3api/s3api_object_handlers_copy.go
index 4dd31c8ce..0c465d3db 100644
--- a/weed/s3api/s3api_object_handlers_copy.go
+++ b/weed/s3api/s3api_object_handlers_copy.go
@@ -171,8 +171,14 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
// Skip encryption-specific headers that might conflict with destination encryption type
skipHeader := false
+ // Skip orphaned SSE-S3 headers (header exists but key is missing)
+ // This prevents confusion about the object's actual encryption state
+ if isOrphanedSSES3Header(k, entry.Extended) {
+ skipHeader = true
+ }
+
// If we're doing cross-encryption, skip conflicting headers
- if len(entry.GetChunks()) > 0 {
+ if !skipHeader && len(entry.GetChunks()) > 0 {
// Detect source and destination encryption types
srcHasSSEC := IsSSECEncrypted(entry.Extended)
srcHasSSEKMS := IsSSEKMSEncrypted(entry.Extended)
@@ -297,7 +303,7 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
// For non-versioned destination, use regular copy
// Remove any versioning-related metadata from source that shouldn't carry over
cleanupVersioningMetadata(dstEntry.Extended)
-
+
dstPath := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, dstBucket, dstObject))
dstDir, dstName := dstPath.DirAndName()
@@ -2350,6 +2356,27 @@ func shouldCreateVersionForCopy(versioningState string) bool {
return versioningState == s3_constants.VersioningEnabled
}
+// isOrphanedSSES3Header checks if a header is an orphaned SSE-S3 encryption header.
+// An orphaned header is one where the encryption indicator exists but the actual key is missing.
+// This can happen when an object was previously encrypted but then copied without encryption,
+// leaving behind the header but removing the key. These orphaned headers should be stripped
+// during copy operations to prevent confusion about the object's actual encryption state.
+// Fixes GitHub issue #7562.
+func isOrphanedSSES3Header(headerKey string, metadata map[string][]byte) bool {
+ if headerKey != s3_constants.AmzServerSideEncryption {
+ return false
+ }
+
+ // The header is AmzServerSideEncryption. Check if its value indicates SSE-S3.
+ if string(metadata[headerKey]) == "AES256" {
+ // It's an SSE-S3 header. It's orphaned if the actual encryption key is missing.
+ _, hasKey := metadata[s3_constants.SeaweedFSSSES3Key]
+ return !hasKey
+ }
+
+ return false
+}
+
// shouldSkipEncryptionHeader determines if a header should be skipped when copying extended attributes
// based on the source and destination encryption types. This consolidates the repetitive logic for
// filtering encryption-related headers during copy operations.