forked from TrueCloudLab/frostfs-s3-gw
[#613] Number of bucket tags increased to 50
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
c5d8e12a1c
commit
42d6fc3fc6
6 changed files with 59 additions and 13 deletions
|
@ -4,6 +4,9 @@ This document outlines major changes between releases.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Number of bucket tags increased to 50 (#613)
|
||||||
|
|
||||||
## [0.32.13] - 2025-03-10
|
## [0.32.13] - 2025-03-10
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -153,7 +153,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.TaggingDirective == replaceDirective {
|
if args.TaggingDirective == replaceDirective {
|
||||||
tagSet, err = parseTaggingHeader(r.Header)
|
tagSet, err = parseObjectTaggingHeader(r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not parse tagging header", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not parse tagging header", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -134,7 +134,7 @@ func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Re
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(r.Header.Get(api.AmzTagging)) > 0 {
|
if len(r.Header.Get(api.AmzTagging)) > 0 {
|
||||||
p.Data.TagSet, err = parseTaggingHeader(r.Header)
|
p.Data.TagSet, err = parseObjectTaggingHeader(r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not parse tagging", reqInfo, err, additional...)
|
h.logAndSendError(ctx, w, "could not parse tagging", reqInfo, err, additional...)
|
||||||
return
|
return
|
||||||
|
|
|
@ -222,7 +222,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tagSet, err := parseTaggingHeader(r.Header)
|
tagSet, err := parseObjectTaggingHeader(r.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not parse tagging header", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not parse tagging header", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -511,7 +511,7 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error()))
|
fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrMalformedXML), err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tagSet, err = h.readTagSet(tags)
|
tagSet, err = readObjectTagSet(tags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not read tag set", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not read tag set", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -742,14 +742,14 @@ func aclHeadersStatus(r *http.Request) aclStatus {
|
||||||
return aclStatusNo
|
return aclStatusNo
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTaggingHeader(header http.Header) (map[string]string, error) {
|
func parseObjectTaggingHeader(header http.Header) (map[string]string, error) {
|
||||||
var tagSet map[string]string
|
var tagSet map[string]string
|
||||||
if tagging := header.Get(api.AmzTagging); len(tagging) > 0 {
|
if tagging := header.Get(api.AmzTagging); len(tagging) > 0 {
|
||||||
queries, err := url.ParseQuery(tagging)
|
queries, err := url.ParseQuery(tagging)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, apierr.GetAPIError(apierr.ErrInvalidArgument)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidArgument)
|
||||||
}
|
}
|
||||||
if len(queries) > maxTags {
|
if len(queries) > maxObjectTags {
|
||||||
return nil, apierr.GetAPIError(apierr.ErrInvalidTagsSizeExceed)
|
return nil, apierr.GetAPIError(apierr.ErrInvalidTagsSizeExceed)
|
||||||
}
|
}
|
||||||
tagSet = make(map[string]string, len(queries))
|
tagSet = make(map[string]string, len(queries))
|
||||||
|
|
|
@ -16,7 +16,8 @@ import (
|
||||||
const (
|
const (
|
||||||
allowedTagChars = "+-=._:/@"
|
allowedTagChars = "+-=._:/@"
|
||||||
|
|
||||||
maxTags = 10
|
maxObjectTags = 10
|
||||||
|
maxBucketTags = 50
|
||||||
keyTagMaxLength = 128
|
keyTagMaxLength = 128
|
||||||
valueTagMaxLength = 256
|
valueTagMaxLength = 256
|
||||||
)
|
)
|
||||||
|
@ -27,7 +28,7 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
|
|
||||||
reqInfo := middleware.GetReqInfo(ctx)
|
reqInfo := middleware.GetReqInfo(ctx)
|
||||||
|
|
||||||
tagSet, err := h.readTagSet(reqInfo.Tagging)
|
tagSet, err := readObjectTagSet(reqInfo.Tagging)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not read tag set", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not read tag set", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -128,7 +129,7 @@ func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
|
|
||||||
reqInfo := middleware.GetReqInfo(ctx)
|
reqInfo := middleware.GetReqInfo(ctx)
|
||||||
|
|
||||||
tagSet, err := h.readTagSet(reqInfo.Tagging)
|
tagSet, err := readBucketTagSet(reqInfo.Tagging)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not read tag set", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not read tag set", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
@ -194,8 +195,16 @@ func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Requ
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) readTagSet(tagging *data.Tagging) (map[string]string, error) {
|
func readObjectTagSet(tagging *data.Tagging) (map[string]string, error) {
|
||||||
if err := checkTagSet(tagging.TagSet); err != nil {
|
return readTagSetBase(tagging, maxObjectTags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBucketTagSet(tagging *data.Tagging) (map[string]string, error) {
|
||||||
|
return readTagSetBase(tagging, maxBucketTags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readTagSetBase(tagging *data.Tagging, maxTags int) (map[string]string, error) {
|
||||||
|
if err := checkTagSet(tagging.TagSet, maxTags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +231,7 @@ func encodeTagging(tagSet map[string]string) *data.Tagging {
|
||||||
return tagging
|
return tagging
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkTagSet(tagSet []data.Tag) error {
|
func checkTagSet(tagSet []data.Tag, maxTags int) error {
|
||||||
if len(tagSet) > maxTags {
|
if len(tagSet) > maxTags {
|
||||||
return errors.GetAPIError(errors.ErrInvalidTagsSizeExceed)
|
return errors.GetAPIError(errors.ErrInvalidTagsSizeExceed)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package handler
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -131,7 +132,40 @@ func TestGetBucketTagging(t *testing.T) {
|
||||||
getBucketTaggingErr(hc, bktName, apierr.GetAPIError(apierr.ErrNoSuchTagSet))
|
getBucketTaggingErr(hc, bktName, apierr.GetAPIError(apierr.ErrNoSuchTagSet))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPutBucketTaggingLimit(t *testing.T) {
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
bktName := "bucket"
|
||||||
|
createBucket(hc, bktName)
|
||||||
|
|
||||||
|
tagsLen := 51
|
||||||
|
tags := make(map[string]string, tagsLen)
|
||||||
|
for i := 0; i < tagsLen; i++ {
|
||||||
|
tags["key"+strconv.Itoa(i)] = "val"
|
||||||
|
}
|
||||||
|
|
||||||
|
putBucketTaggingErr(hc, bktName, tags, apierr.ErrInvalidTagsSizeExceed)
|
||||||
|
delete(tags, "key0")
|
||||||
|
|
||||||
|
putBucketTagging(hc, bktName, tags)
|
||||||
|
|
||||||
|
tagSet := getBucketTagging(hc, bktName)
|
||||||
|
require.Len(t, tagSet.TagSet, 50)
|
||||||
|
|
||||||
|
putBucketTagging(hc, bktName, nil)
|
||||||
|
getBucketTaggingErr(hc, bktName, apierr.GetAPIError(apierr.ErrNoSuchTagSet))
|
||||||
|
}
|
||||||
|
|
||||||
func putBucketTagging(hc *handlerContext, bktName string, tags map[string]string) {
|
func putBucketTagging(hc *handlerContext, bktName string, tags map[string]string) {
|
||||||
|
w := putBucketTaggingBase(hc, bktName, tags)
|
||||||
|
assertStatus(hc.t, w, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putBucketTaggingErr(hc *handlerContext, bktName string, tags map[string]string, errCode apierr.ErrorCode) {
|
||||||
|
w := putBucketTaggingBase(hc, bktName, tags)
|
||||||
|
assertS3Error(hc.t, w, apierr.GetAPIError(errCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
func putBucketTaggingBase(hc *handlerContext, bktName string, tags map[string]string) *httptest.ResponseRecorder {
|
||||||
body := &data.Tagging{
|
body := &data.Tagging{
|
||||||
TagSet: make([]data.Tag, 0, len(tags)),
|
TagSet: make([]data.Tag, 0, len(tags)),
|
||||||
}
|
}
|
||||||
|
@ -146,7 +180,7 @@ func putBucketTagging(hc *handlerContext, bktName string, tags map[string]string
|
||||||
w, r := prepareTestRequest(hc, bktName, "", body)
|
w, r := prepareTestRequest(hc, bktName, "", body)
|
||||||
middleware.GetReqInfo(r.Context()).Tagging = body
|
middleware.GetReqInfo(r.Context()).Tagging = body
|
||||||
hc.Handler().PutBucketTaggingHandler(w, r)
|
hc.Handler().PutBucketTaggingHandler(w, r)
|
||||||
assertStatus(hc.t, w, http.StatusOK)
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBucketTagging(hc *handlerContext, bktName string) *data.Tagging {
|
func getBucketTagging(hc *handlerContext, bktName string) *data.Tagging {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue