mirror of
https://github.com/minio/minio.git
synced 2025-11-09 21:49:46 -05:00
Add x-amz-expiration header in some S3 responses (#9667)
x-amz-expiration is described in the S3 specification as a header which indicates if the object in question will expire any time in the future.
This commit is contained in:
@@ -80,6 +80,9 @@ const (
|
||||
// Multipart parts count
|
||||
AmzMpPartsCount = "x-amz-mp-parts-count"
|
||||
|
||||
// Object date/time of expiration
|
||||
AmzExpiration = "x-amz-expiration"
|
||||
|
||||
// Dummy putBucketACL
|
||||
AmzACL = "x-amz-acl"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"time"
|
||||
@@ -252,6 +253,19 @@ func isETagEqual(left, right string) bool {
|
||||
return canonicalizeETag(left) == canonicalizeETag(right)
|
||||
}
|
||||
|
||||
// setAmzExpirationHeader sets x-amz-expiration header with expiry time
|
||||
// after analyzing the current bucket lifecycle rules if any.
|
||||
func setAmzExpirationHeader(w http.ResponseWriter, bucket string, objInfo ObjectInfo) {
|
||||
if lc, err := globalLifecycleSys.Get(bucket); err == nil {
|
||||
ruleID, expiryTime := lc.PredictExpiryTime(objInfo.Name, objInfo.UserTags)
|
||||
if !expiryTime.IsZero() {
|
||||
w.Header()[xhttp.AmzExpiration] = []string{
|
||||
fmt.Sprintf(`expiry-date="%s", rule-id="%s"`, expiryTime.Format(http.TimeFormat), ruleID),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deleteObject is a convenient wrapper to delete an object, this
|
||||
// is a common function to be called from object handlers and
|
||||
// web handlers.
|
||||
|
||||
@@ -427,6 +427,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
setHeadGetRespHeaders(w, r.URL.Query())
|
||||
setAmzExpirationHeader(w, bucket, objInfo)
|
||||
|
||||
statusCodeWritten := false
|
||||
httpWriter := ioutil.WriteOnClose(w)
|
||||
@@ -606,6 +607,9 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
// Set any additional requested response headers.
|
||||
setHeadGetRespHeaders(w, r.URL.Query())
|
||||
|
||||
// Set the expiration header
|
||||
setAmzExpirationHeader(w, bucket, objInfo)
|
||||
|
||||
// Successful response.
|
||||
if rs != nil {
|
||||
w.WriteHeader(http.StatusPartialContent)
|
||||
@@ -1165,6 +1169,8 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
}
|
||||
|
||||
setAmzExpirationHeader(w, dstBucket, objInfo)
|
||||
|
||||
response := generateCopyObjectResponse(getDecryptedETag(r.Header, objInfo, false), objInfo.ModTime)
|
||||
encodedSuccessResponse := encodeResponse(response)
|
||||
|
||||
@@ -1476,10 +1482,14 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We must not use the http.Header().Set method here because some (broken)
|
||||
// clients expect the ETag header key to be literally "ETag" - not "Etag" (case-sensitive).
|
||||
// Therefore, we have to set the ETag directly as map entry.
|
||||
w.Header()[xhttp.ETag] = []string{`"` + etag + `"`}
|
||||
|
||||
setAmzExpirationHeader(w, bucket, objInfo)
|
||||
|
||||
writeSuccessResponseHeadersOnly(w)
|
||||
|
||||
// Notify object created event.
|
||||
@@ -2526,6 +2536,8 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
||||
// Set etag.
|
||||
w.Header()[xhttp.ETag] = []string{"\"" + objInfo.ETag + "\""}
|
||||
|
||||
setAmzExpirationHeader(w, bucket, objInfo)
|
||||
|
||||
// Write success response.
|
||||
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user