From 05a6c170bf0c602d6fbd1bf2d536ef3b6eaf3b6e Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Thu, 19 Sep 2024 05:59:07 -0700 Subject: [PATCH] Fix PutObject Trailing checksum (#20456) PutObject would verify trailing checksums, but not store them. Fixes #20455 --- cmd/erasure-object.go | 13 ++++++++----- cmd/object-handlers.go | 1 + internal/hash/checksum.go | 4 ++++ internal/hash/reader.go | 8 ++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/cmd/erasure-object.go b/cmd/erasure-object.go index de0c4082f..6c84c96eb 100644 --- a/cmd/erasure-object.go +++ b/cmd/erasure-object.go @@ -1329,10 +1329,6 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st } fi.DataDir = mustGetUUID() - fi.Checksum = opts.WantChecksum.AppendTo(nil, nil) - if opts.EncryptFn != nil { - fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum) - } if ckSum := userDefined[ReplicationSsecChecksumHeader]; ckSum != "" { if v, err := base64.StdEncoding.DecodeString(ckSum); err == nil { fi.Checksum = v @@ -1460,7 +1456,13 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st actualSize = n } } - + if fi.Checksum == nil { + // Trailing headers checksums should now be filled. + fi.Checksum = opts.WantChecksum.AppendTo(nil, nil) + if opts.EncryptFn != nil { + fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum) + } + } for i, w := range writers { if w == nil { onlineDisks[i] = nil @@ -1474,6 +1476,7 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st // No need to add checksum to part. We already have it on the object. partsMetadata[i].AddObjectPart(1, "", n, actualSize, modTime, compIndex, nil) partsMetadata[i].Versioned = opts.Versioned || opts.VersionSuspended + partsMetadata[i].Checksum = fi.Checksum } userDefined["etag"] = r.MD5CurrentHexString() diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 00e74d9c5..3443ecd41 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -1960,6 +1960,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req return } opts.IndexCB = idxCb + opts.WantChecksum = hashReader.Checksum() if opts.PreserveETag != "" || r.Header.Get(xhttp.IfMatch) != "" || diff --git a/internal/hash/checksum.go b/internal/hash/checksum.go index 1466cec13..a169e5acf 100644 --- a/internal/hash/checksum.go +++ b/internal/hash/checksum.go @@ -335,6 +335,10 @@ func (c *Checksum) AppendTo(b []byte, parts []byte) []byte { var tmp [binary.MaxVarintLen32]byte n := binary.PutUvarint(tmp[:], uint64(c.Type)) crc := c.Raw + if c.Type.Trailing() { + // When we serialize we don't care if it was trailing. + c.Type ^= ChecksumTrailing + } if len(crc) != c.Type.RawByteLen() { return b } diff --git a/internal/hash/reader.go b/internal/hash/reader.go index f849a69f0..272452f06 100644 --- a/internal/hash/reader.go +++ b/internal/hash/reader.go @@ -366,6 +366,14 @@ func (r *Reader) ContentCRC() map[string]string { return map[string]string{r.contentHash.Type.String(): r.contentHash.Encoded} } +// Checksum returns the content checksum if set. +func (r *Reader) Checksum() *Checksum { + if !r.contentHash.Type.IsSet() || !r.contentHash.Valid() { + return nil + } + return &r.contentHash +} + var _ io.Closer = (*Reader)(nil) // compiler check // Close and release resources.