fix: conditional checks write for multipart (#21567)

This commit is contained in:
M Alvee 2025-09-07 09:13:09 -07:00 committed by GitHub
parent 0cde982902
commit 07c3a429bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 25 additions and 2 deletions

View File

@ -393,6 +393,12 @@ func (er erasureObjects) newMultipartUpload(ctx context.Context, bucket string,
if err != nil && !isErrVersionNotFound(err) && !isErrObjectNotFound(err) && !isErrReadQuorum(err) {
return nil, err
}
// if object doesn't exist and not a replication request return error for If-Match conditional requests
// If-None-Match should be allowed to proceed for non-existent objects
if err != nil && !opts.ReplicationRequest && opts.HasIfMatch && (isErrObjectNotFound(err) || isErrVersionNotFound(err)) {
return nil, err
}
}
userDefined := cloneMSS(opts.UserDefined)
@ -1111,6 +1117,12 @@ func (er erasureObjects) CompleteMultipartUpload(ctx context.Context, bucket str
if err != nil && !isErrVersionNotFound(err) && !isErrObjectNotFound(err) && !isErrReadQuorum(err) {
return ObjectInfo{}, err
}
// if object doesn't exist and not a replication request return error for If-Match conditional requests
// If-None-Match should be allowed to proceed for non-existent objects
if err != nil && !opts.ReplicationRequest && opts.HasIfMatch && (isErrObjectNotFound(err) || isErrVersionNotFound(err)) {
return ObjectInfo{}, err
}
}
fi, partsMetadata, err := er.checkUploadIDExists(ctx, bucket, object, uploadID, true)

View File

@ -1278,8 +1278,9 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
return objInfo, err
}
// if object doesn't exist and not a replication request return error for conditional requests
if err != nil && !opts.ReplicationRequest {
// if object doesn't exist and not a replication request return error for If-Match conditional requests
// If-None-Match should be allowed to proceed for non-existent objects
if err != nil && !opts.ReplicationRequest && opts.HasIfMatch && (isErrObjectNotFound(err) || isErrVersionNotFound(err)) {
return objInfo, err
}
}

View File

@ -91,6 +91,7 @@ type ObjectOptions struct {
NoDecryption bool // indicates if the stream must be decrypted.
PreserveETag string // preserves this etag during a PUT call.
NoLock bool // indicates to lower layers if the caller is expecting to hold locks.
HasIfMatch bool // indicates if the request has If-Match header
ProxyRequest bool // only set for GET/HEAD in active-active replication scenario
ProxyHeaderSet bool // only set for GET/HEAD in active-active replication scenario
ReplicationRequest bool // true only if replication request

View File

@ -2014,6 +2014,9 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
pReader := NewPutObjReader(rawReader)
opts.IndexCB = idxCb
if r.Header.Get(xhttp.IfMatch) != "" {
opts.HasIfMatch = true
}
if opts.PreserveETag != "" ||
r.Header.Get(xhttp.IfMatch) != "" ||
r.Header.Get(xhttp.IfNoneMatch) != "" {

View File

@ -200,6 +200,9 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
return
}
if r.Header.Get(xhttp.IfMatch) != "" {
opts.HasIfMatch = true
}
if opts.PreserveETag != "" ||
r.Header.Get(xhttp.IfMatch) != "" ||
r.Header.Get(xhttp.IfNoneMatch) != "" {
@ -1014,6 +1017,9 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
multipartETag := etag.Multipart(completeETags...)
opts.UserDefined["etag"] = multipartETag.String()
if r.Header.Get(xhttp.IfMatch) != "" {
opts.HasIfMatch = true
}
if opts.PreserveETag != "" ||
r.Header.Get(xhttp.IfMatch) != "" ||
r.Header.Get(xhttp.IfNoneMatch) != "" {