mirror of https://github.com/minio/minio.git
return tags as part of Head/Get calls (#17635)
AWS S3 only returns the number of tag counts, along with that we must return the tags as well to avoid another metadata call to the server.
This commit is contained in:
parent
e1094dde08
commit
7764f4a8e3
|
@ -23,11 +23,11 @@ import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/v7/pkg/tags"
|
||||||
"github.com/minio/minio/internal/crypto"
|
"github.com/minio/minio/internal/crypto"
|
||||||
xhttp "github.com/minio/minio/internal/http"
|
xhttp "github.com/minio/minio/internal/http"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
|
@ -140,9 +140,13 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp
|
||||||
|
|
||||||
// Set tag count if object has tags
|
// Set tag count if object has tags
|
||||||
if len(objInfo.UserTags) > 0 {
|
if len(objInfo.UserTags) > 0 {
|
||||||
tags, _ := url.ParseQuery(objInfo.UserTags)
|
tags, _ := tags.ParseObjectTags(objInfo.UserTags)
|
||||||
if len(tags) > 0 {
|
if tags.Count() > 0 {
|
||||||
w.Header()[xhttp.AmzTagCount] = []string{strconv.Itoa(len(tags))}
|
w.Header()[xhttp.AmzTagCount] = []string{strconv.Itoa(tags.Count())}
|
||||||
|
if opts.Tagging {
|
||||||
|
// This is MinIO only extension to return back tags along with the count.
|
||||||
|
w.Header()[xhttp.AmzObjectTagging] = []string{objInfo.UserTags}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
const (
|
const (
|
||||||
copyDirective = "COPY"
|
copyDirective = "COPY"
|
||||||
replaceDirective = "REPLACE"
|
replaceDirective = "REPLACE"
|
||||||
|
accessDirective = "ACCESS"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parses location constraint from the incoming reader.
|
// Parses location constraint from the incoming reader.
|
||||||
|
|
|
@ -55,6 +55,7 @@ type ObjectOptions struct {
|
||||||
|
|
||||||
DeleteMarker bool // Is only set in DELETE operations for delete marker replication
|
DeleteMarker bool // Is only set in DELETE operations for delete marker replication
|
||||||
CheckDMReplicationReady bool // Is delete marker ready to be replicated - set only during HEAD
|
CheckDMReplicationReady bool // Is delete marker ready to be replicated - set only during HEAD
|
||||||
|
Tagging bool // Is only in GET/HEAD operations to return tagging metadata along with regular metadata and body.
|
||||||
|
|
||||||
UserDefined map[string]string // only set in case of POST/PUT operations
|
UserDefined map[string]string // only set in case of POST/PUT operations
|
||||||
PartNumber int // only useful in case of GetObject/HeadObject
|
PartNumber int // only useful in case of GetObject/HeadObject
|
||||||
|
|
|
@ -108,21 +108,11 @@ func getOpts(ctx context.Context, r *http.Request, bucket, object string) (Objec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePrefix := false
|
|
||||||
if d := r.Header.Get(xhttp.MinIOForceDelete); d != "" {
|
|
||||||
if b, err := strconv.ParseBool(d); err == nil {
|
|
||||||
deletePrefix = b
|
|
||||||
} else {
|
|
||||||
return opts, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// default case of passing encryption headers to backend
|
// default case of passing encryption headers to backend
|
||||||
opts, err = getDefaultOpts(r.Header, false, nil)
|
opts, err = getDefaultOpts(r.Header, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return opts, err
|
return opts, err
|
||||||
}
|
}
|
||||||
opts.DeletePrefix = deletePrefix
|
|
||||||
opts.PartNumber = partNumber
|
opts.PartNumber = partNumber
|
||||||
opts.VersionID = vid
|
opts.VersionID = vid
|
||||||
delMarker := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceDeleteMarker))
|
delMarker := strings.TrimSpace(r.Header.Get(xhttp.MinIOSourceDeleteMarker))
|
||||||
|
@ -157,7 +147,7 @@ func getOpts(ctx context.Context, r *http.Request, bucket, object string) (Objec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
opts.Tagging = r.Header.Get(xhttp.AmzTagDirective) == accessDirective
|
||||||
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(bucket, object)
|
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(bucket, object)
|
||||||
opts.VersionSuspended = globalBucketVersioningSys.PrefixSuspended(bucket, object)
|
opts.VersionSuspended = globalBucketVersioningSys.PrefixSuspended(bucket, object)
|
||||||
return opts, nil
|
return opts, nil
|
||||||
|
@ -168,6 +158,17 @@ func delOpts(ctx context.Context, r *http.Request, bucket, object string) (opts
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return opts, err
|
return opts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deletePrefix := false
|
||||||
|
if d := r.Header.Get(xhttp.MinIOForceDelete); d != "" {
|
||||||
|
if b, err := strconv.ParseBool(d); err == nil {
|
||||||
|
deletePrefix = b
|
||||||
|
} else {
|
||||||
|
return opts, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.DeletePrefix = deletePrefix
|
||||||
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(bucket, object)
|
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(bucket, object)
|
||||||
// Objects matching prefixes should not leave delete markers,
|
// Objects matching prefixes should not leave delete markers,
|
||||||
// dramatically reduces namespace pollution while keeping the
|
// dramatically reduces namespace pollution while keeping the
|
||||||
|
|
Loading…
Reference in New Issue