mirror of https://github.com/minio/minio.git
Remove checksums from HTTP range request, add part checksums (#17105)
This commit is contained in:
parent
6e27264c6b
commit
7fad0c8b41
|
@ -743,7 +743,7 @@ func generateInitiateMultipartUploadResponse(bucket, key, uploadID string) Initi
|
||||||
|
|
||||||
// generates CompleteMultipartUploadResponse for given bucket, key, location and ETag.
|
// generates CompleteMultipartUploadResponse for given bucket, key, location and ETag.
|
||||||
func generateCompleteMultpartUploadResponse(bucket, key, location string, oi ObjectInfo) CompleteMultipartUploadResponse {
|
func generateCompleteMultpartUploadResponse(bucket, key, location string, oi ObjectInfo) CompleteMultipartUploadResponse {
|
||||||
cs := oi.decryptChecksums()
|
cs := oi.decryptChecksums(0)
|
||||||
c := CompleteMultipartUploadResponse{
|
c := CompleteMultipartUploadResponse{
|
||||||
Location: location,
|
Location: location,
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
|
|
|
@ -1124,7 +1124,8 @@ func (o *ObjectInfo) metadataEncryptFn(headers http.Header) (objectMetaEncryptFn
|
||||||
}
|
}
|
||||||
|
|
||||||
// decryptChecksums will attempt to decode checksums and return it/them if set.
|
// decryptChecksums will attempt to decode checksums and return it/them if set.
|
||||||
func (o *ObjectInfo) decryptChecksums() map[string]string {
|
// if part > 0, and we have the checksum for the part that will be returned.
|
||||||
|
func (o *ObjectInfo) decryptChecksums(part int) map[string]string {
|
||||||
data := o.Checksum
|
data := o.Checksum
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1137,5 +1138,5 @@ func (o *ObjectInfo) decryptChecksums() map[string]string {
|
||||||
}
|
}
|
||||||
data = decrypted
|
data = decrypted
|
||||||
}
|
}
|
||||||
return hash.ReadCheckSums(data)
|
return hash.ReadCheckSums(data, part)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1135,9 +1135,9 @@ func (er erasureObjects) CompleteMultipartUpload(ctx context.Context, bucket str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checksumType.IsSet() {
|
if checksumType.IsSet() {
|
||||||
checksumType |= hash.ChecksumMultipart
|
checksumType |= hash.ChecksumMultipart | hash.ChecksumIncludesMultipart
|
||||||
cs := hash.NewChecksumFromData(checksumType, checksumCombined)
|
cs := hash.NewChecksumFromData(checksumType, checksumCombined)
|
||||||
fi.Checksum = cs.AppendTo(nil, len(fi.Parts))
|
fi.Checksum = cs.AppendTo(nil, checksumCombined)
|
||||||
if opts.EncryptFn != nil {
|
if opts.EncryptFn != nil {
|
||||||
fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum)
|
fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
|
||||||
}
|
}
|
||||||
|
|
||||||
fi.DataDir = mustGetUUID()
|
fi.DataDir = mustGetUUID()
|
||||||
fi.Checksum = opts.WantChecksum.AppendTo(nil, 0)
|
fi.Checksum = opts.WantChecksum.AppendTo(nil, nil)
|
||||||
if opts.EncryptFn != nil {
|
if opts.EncryptFn != nil {
|
||||||
fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum)
|
fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum)
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,7 @@ func setPutObjHeaders(w http.ResponseWriter, objInfo ObjectInfo, delete bool) {
|
||||||
lc.SetPredictionHeaders(w, objInfo.ToLifecycleOpts())
|
lc.SetPredictionHeaders(w, objInfo.ToLifecycleOpts())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hash.AddChecksumHeader(w, objInfo.decryptChecksums())
|
hash.AddChecksumHeader(w, objInfo.decryptChecksums(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteObjectVersions(ctx context.Context, o ObjectLayer, bucket string, toDel []ObjectToDelete) {
|
func deleteObjectVersions(ctx context.Context, o ObjectLayer, bucket string, toDel []ObjectToDelete) {
|
||||||
|
|
|
@ -513,8 +513,9 @@ func (api objectAPIHandlers) getObjectHandler(ctx context.Context, objectAPI Obj
|
||||||
w.Header().Set(xhttp.AmzServerSideEncryptionCustomerKeyMD5, r.Header.Get(xhttp.AmzServerSideEncryptionCustomerKeyMD5))
|
w.Header().Set(xhttp.AmzServerSideEncryptionCustomerKeyMD5, r.Header.Get(xhttp.AmzServerSideEncryptionCustomerKeyMD5))
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get(xhttp.AmzChecksumMode) == "ENABLED" {
|
if r.Header.Get(xhttp.AmzChecksumMode) == "ENABLED" && rs == nil {
|
||||||
hash.AddChecksumHeader(w, objInfo.decryptChecksums())
|
// AWS S3 silently drops checksums on range requests.
|
||||||
|
hash.AddChecksumHeader(w, objInfo.decryptChecksums(opts.PartNumber))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = setObjectHeaders(w, objInfo, rs, opts); err != nil {
|
if err = setObjectHeaders(w, objInfo, rs, opts); err != nil {
|
||||||
|
@ -800,8 +801,9 @@ func (api objectAPIHandlers) headObjectHandler(ctx context.Context, objectAPI Ob
|
||||||
w.Header().Set(xhttp.AmzServerSideEncryptionCustomerKeyMD5, r.Header.Get(xhttp.AmzServerSideEncryptionCustomerKeyMD5))
|
w.Header().Set(xhttp.AmzServerSideEncryptionCustomerKeyMD5, r.Header.Get(xhttp.AmzServerSideEncryptionCustomerKeyMD5))
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get(xhttp.AmzChecksumMode) == "ENABLED" {
|
if r.Header.Get(xhttp.AmzChecksumMode) == "ENABLED" && rs == nil {
|
||||||
hash.AddChecksumHeader(w, objInfo.decryptChecksums())
|
// AWS S3 silently drops checksums on range requests.
|
||||||
|
hash.AddChecksumHeader(w, objInfo.decryptChecksums(opts.PartNumber))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set standard object headers.
|
// Set standard object headers.
|
||||||
|
|
|
@ -19,6 +19,7 @@ package hash
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
@ -30,6 +31,7 @@ import (
|
||||||
|
|
||||||
"github.com/minio/minio/internal/hash/sha256"
|
"github.com/minio/minio/internal/hash/sha256"
|
||||||
xhttp "github.com/minio/minio/internal/http"
|
xhttp "github.com/minio/minio/internal/http"
|
||||||
|
"github.com/minio/minio/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MinIOMultipartChecksum is as metadata on multipart uploads to indicate checksum type.
|
// MinIOMultipartChecksum is as metadata on multipart uploads to indicate checksum type.
|
||||||
|
@ -56,6 +58,8 @@ const (
|
||||||
ChecksumInvalid
|
ChecksumInvalid
|
||||||
// ChecksumMultipart indicates the checksum is from a multipart upload.
|
// ChecksumMultipart indicates the checksum is from a multipart upload.
|
||||||
ChecksumMultipart
|
ChecksumMultipart
|
||||||
|
// ChecksumIncludesMultipart indicates the checksum also contains part checksums.
|
||||||
|
ChecksumIncludesMultipart
|
||||||
|
|
||||||
// ChecksumNone indicates no checksum.
|
// ChecksumNone indicates no checksum.
|
||||||
ChecksumNone ChecksumType = 0
|
ChecksumNone ChecksumType = 0
|
||||||
|
@ -183,7 +187,7 @@ func NewChecksumFromData(t ChecksumType, data []byte) *Checksum {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadCheckSums will read checksums from b and return them.
|
// ReadCheckSums will read checksums from b and return them.
|
||||||
func ReadCheckSums(b []byte) map[string]string {
|
func ReadCheckSums(b []byte, part int) map[string]string {
|
||||||
res := make(map[string]string, 1)
|
res := make(map[string]string, 1)
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
t, n := binary.Uvarint(b)
|
t, n := binary.Uvarint(b)
|
||||||
|
@ -206,8 +210,29 @@ func ReadCheckSums(b []byte) map[string]string {
|
||||||
}
|
}
|
||||||
cs = fmt.Sprintf("%s-%d", cs, t)
|
cs = fmt.Sprintf("%s-%d", cs, t)
|
||||||
b = b[n:]
|
b = b[n:]
|
||||||
|
if part > 0 {
|
||||||
|
cs = ""
|
||||||
|
}
|
||||||
|
if typ.Is(ChecksumIncludesMultipart) {
|
||||||
|
wantLen := int(t) * length
|
||||||
|
if len(b) < wantLen {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Read part checksum
|
||||||
|
if part > 0 && uint64(part) <= t {
|
||||||
|
offset := (part - 1) * length
|
||||||
|
partCs := b[offset:]
|
||||||
|
cs = base64.StdEncoding.EncodeToString(partCs[:length])
|
||||||
|
}
|
||||||
|
b = b[wantLen:]
|
||||||
|
}
|
||||||
|
} else if part > 1 {
|
||||||
|
// For non-multipart, checksum is part 1.
|
||||||
|
cs = ""
|
||||||
|
}
|
||||||
|
if cs != "" {
|
||||||
|
res[typ.String()] = cs
|
||||||
}
|
}
|
||||||
res[typ.String()] = cs
|
|
||||||
}
|
}
|
||||||
if len(res) == 0 {
|
if len(res) == 0 {
|
||||||
res = nil
|
res = nil
|
||||||
|
@ -239,7 +264,7 @@ func NewChecksumString(alg, value string) *Checksum {
|
||||||
// AppendTo will append the checksum to b.
|
// AppendTo will append the checksum to b.
|
||||||
// 'parts' is used when checksum has ChecksumMultipart set.
|
// 'parts' is used when checksum has ChecksumMultipart set.
|
||||||
// ReadCheckSums reads the values back.
|
// ReadCheckSums reads the values back.
|
||||||
func (c *Checksum) AppendTo(b []byte, parts int) []byte {
|
func (c *Checksum) AppendTo(b []byte, parts []byte) []byte {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -252,11 +277,23 @@ func (c *Checksum) AppendTo(b []byte, parts int) []byte {
|
||||||
b = append(b, tmp[:n]...)
|
b = append(b, tmp[:n]...)
|
||||||
b = append(b, crc...)
|
b = append(b, crc...)
|
||||||
if c.Type.Is(ChecksumMultipart) {
|
if c.Type.Is(ChecksumMultipart) {
|
||||||
if parts < 0 {
|
var checksums int
|
||||||
parts = 0
|
// Ensure we don't divide by 0:
|
||||||
|
if c.Type.RawByteLen() == 0 || len(parts)%c.Type.RawByteLen() != 0 {
|
||||||
|
logger.LogIf(context.Background(), fmt.Errorf("internal error: Unexpected checksum length: %d, each checksum %d", len(parts), c.Type.RawByteLen()))
|
||||||
|
checksums = 0
|
||||||
|
parts = nil
|
||||||
|
} else {
|
||||||
|
checksums = len(parts) / c.Type.RawByteLen()
|
||||||
}
|
}
|
||||||
n := binary.PutUvarint(tmp[:], uint64(parts))
|
if !c.Type.Is(ChecksumIncludesMultipart) {
|
||||||
|
parts = nil
|
||||||
|
}
|
||||||
|
n := binary.PutUvarint(tmp[:], uint64(checksums))
|
||||||
b = append(b, tmp[:n]...)
|
b = append(b, tmp[:n]...)
|
||||||
|
if len(parts) > 0 {
|
||||||
|
b = append(b, parts...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue