azure/s3 gateways: Pass ETag during GET call to avoid data corruption (#11024)

Both Azure & S3 gateways call for object information before returning
the stream of the object, however, the object content/length could be
modified meanwhile, which means it can return a corrupted object.

Use ETag to ensure that the object was not modified during the GET call
master
Anis Elleuch 4 years ago committed by GitHub
parent 970ddb424b
commit cffdb01279
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      cmd/gateway/azure/gateway-azure.go
  2. 5
      cmd/gateway/s3/gateway-s3.go
  3. 3
      cmd/object-api-datatypes.go

@ -812,7 +812,7 @@ func (a *azureObjects) GetObjectNInfo(ctx context.Context, bucket, object string
pr, pw := io.Pipe() pr, pw := io.Pipe()
go func() { go func() {
err := a.GetObject(ctx, bucket, object, startOffset, length, pw, objInfo.ETag, opts) err := a.GetObject(ctx, bucket, object, startOffset, length, pw, objInfo.InnerETag, opts)
pw.CloseWithError(err) pw.CloseWithError(err)
}() }()
// Setup cleanup function to cause the above go-routine to // Setup cleanup function to cause the above go-routine to
@ -833,8 +833,13 @@ func (a *azureObjects) GetObject(ctx context.Context, bucket, object string, sta
return azureToObjectError(minio.InvalidRange{}, bucket, object) return azureToObjectError(minio.InvalidRange{}, bucket, object)
} }
accessCond := azblob.BlobAccessConditions{}
if etag != "" {
accessCond.ModifiedAccessConditions.IfMatch = azblob.ETag(etag)
}
blobURL := a.client.NewContainerURL(bucket).NewBlobURL(object) blobURL := a.client.NewContainerURL(bucket).NewBlobURL(object)
blob, err := blobURL.Download(ctx, startOffset, length, azblob.BlobAccessConditions{}, false) blob, err := blobURL.Download(ctx, startOffset, length, accessCond, false)
if err != nil { if err != nil {
return azureToObjectError(err, bucket, object) return azureToObjectError(err, bucket, object)
} }
@ -855,6 +860,8 @@ func (a *azureObjects) GetObjectInfo(ctx context.Context, bucket, object string,
return objInfo, azureToObjectError(err, bucket, object) return objInfo, azureToObjectError(err, bucket, object)
} }
realETag := string(blob.ETag())
// Populate correct ETag's if possible, this code primarily exists // Populate correct ETag's if possible, this code primarily exists
// because AWS S3 indicates that // because AWS S3 indicates that
// //
@ -866,7 +873,7 @@ func (a *azureObjects) GetObjectInfo(ctx context.Context, bucket, object string,
// //
// Some applications depend on this behavior refer https://github.com/minio/minio/issues/6550 // Some applications depend on this behavior refer https://github.com/minio/minio/issues/6550
// So we handle it here and make this consistent. // So we handle it here and make this consistent.
etag := minio.ToS3ETag(string(blob.ETag())) etag := minio.ToS3ETag(realETag)
metadata := blob.NewMetadata() metadata := blob.NewMetadata()
contentMD5 := blob.ContentMD5() contentMD5 := blob.ContentMD5()
switch { switch {
@ -881,6 +888,7 @@ func (a *azureObjects) GetObjectInfo(ctx context.Context, bucket, object string,
Bucket: bucket, Bucket: bucket,
UserDefined: azurePropertiesToS3Meta(metadata, blob.NewHTTPHeaders(), blob.ContentLength()), UserDefined: azurePropertiesToS3Meta(metadata, blob.NewHTTPHeaders(), blob.ContentLength()),
ETag: etag, ETag: etag,
InnerETag: realETag,
ModTime: blob.LastModified(), ModTime: blob.LastModified(),
Name: object, Name: object,
Size: blob.ContentLength(), Size: blob.ContentLength(),

@ -431,6 +431,11 @@ func (l *s3Objects) GetObject(ctx context.Context, bucket string, key string, st
return minio.ErrorRespToObjectError(err, bucket, key) return minio.ErrorRespToObjectError(err, bucket, key)
} }
} }
if etag != "" {
opts.SetMatchETag(etag)
}
object, _, _, err := l.Client.GetObject(ctx, bucket, key, opts) object, _, _, err := l.Client.GetObject(ctx, bucket, key, opts)
if err != nil { if err != nil {
return minio.ErrorRespToObjectError(err, bucket, key) return minio.ErrorRespToObjectError(err, bucket, key)

@ -168,6 +168,9 @@ type ObjectInfo struct {
// Hex encoded unique entity tag of the object. // Hex encoded unique entity tag of the object.
ETag string ETag string
// The ETag stored in the gateway backend
InnerETag string
// Version ID of this object. // Version ID of this object.
VersionID string VersionID string

Loading…
Cancel
Save