diff --git a/cmd/object-handlers-common.go b/cmd/object-handlers-common.go index 4ba960b3c..d3aa0b600 100644 --- a/cmd/object-handlers-common.go +++ b/cmd/object-handlers-common.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 MinIO, Inc. +// Copyright (c) 2015-2023 MinIO, Inc. // // This file is part of MinIO Object Storage stack // @@ -165,6 +165,30 @@ func checkPreconditionsPUT(ctx context.Context, w http.ResponseWriter, r *http.R } } + // If-Match : Return the object only if its entity tag (ETag) is the same as the one specified; + // otherwise return a 412 (precondition failed). + ifMatchETagHeader := r.Header.Get(xhttp.IfMatch) + if ifMatchETagHeader != "" { + if !isETagEqual(objInfo.ETag, ifMatchETagHeader) { + // If the object ETag does not match with the specified ETag. + writeHeaders() + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL) + return true + } + } + + // If-None-Match : Return the object only if its entity tag (ETag) is different from the + // one specified otherwise, return a 304 (not modified). + ifNoneMatchETagHeader := r.Header.Get(xhttp.IfNoneMatch) + if ifNoneMatchETagHeader != "" { + if isETagEqual(objInfo.ETag, ifNoneMatchETagHeader) { + // If the object ETag matches with the specified ETag. + writeHeaders() + w.WriteHeader(http.StatusNotModified) + return true + } + } + etagMatch := opts.PreserveETag != "" && isETagEqual(objInfo.ETag, opts.PreserveETag) vidMatch := opts.VersionID != "" && opts.VersionID == objInfo.VersionID mtimeMatch := !opts.MTime.IsZero() && objInfo.ModTime.Unix() >= opts.MTime.Unix() diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index d720fdab4..1b8db90f2 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -1769,7 +1769,9 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req } opts.IndexCB = idxCb - if !opts.MTime.IsZero() && opts.PreserveETag != "" { + if (!opts.MTime.IsZero() && opts.PreserveETag != "") || + r.Header.Get(xhttp.IfMatch) != "" || + r.Header.Get(xhttp.IfNoneMatch) != "" { opts.CheckPrecondFn = func(oi ObjectInfo) bool { if _, err := DecryptObjectInfo(&oi, r); err != nil { writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)