Skip to content

Commit dfb0b24

Browse files
authoredFeb 20, 2025··
tags were incorrectly used, fix them use the right package (#2070)
1 parent 52f0eda commit dfb0b24

File tree

5 files changed

+19
-120
lines changed

5 files changed

+19
-120
lines changed
 

Diff for: ‎api-compose-object.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/google/uuid"
3131
"github.com/minio/minio-go/v7/pkg/encrypt"
3232
"github.com/minio/minio-go/v7/pkg/s3utils"
33+
"github.com/minio/minio-go/v7/pkg/tags"
3334
)
3435

3536
// CopyDestOptions represents options specified by user for CopyObject/ComposeObject APIs
@@ -98,8 +99,8 @@ func (opts CopyDestOptions) Marshal(header http.Header) {
9899
const replaceDirective = "REPLACE"
99100
if opts.ReplaceTags {
100101
header.Set(amzTaggingHeaderDirective, replaceDirective)
101-
if tags := s3utils.TagEncode(opts.UserTags); tags != "" {
102-
header.Set(amzTaggingHeader, tags)
102+
if tags, _ := tags.NewTags(opts.UserTags, true); tags != nil {
103+
header.Set(amzTaggingHeader, tags.String())
103104
}
104105
}
105106

@@ -236,7 +237,9 @@ func (c *Client) copyObjectDo(ctx context.Context, srcBucket, srcObject, destBuc
236237
}
237238

238239
if len(dstOpts.UserTags) != 0 {
239-
headers.Set(amzTaggingHeader, s3utils.TagEncode(dstOpts.UserTags))
240+
if tags, _ := tags.NewTags(dstOpts.UserTags, true); tags != nil {
241+
headers.Set(amzTaggingHeader, tags.String())
242+
}
240243
}
241244

242245
reqMetadata := requestMetadata{

Diff for: ‎api-put-object.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
"github.com/minio/minio-go/v7/pkg/encrypt"
3232
"github.com/minio/minio-go/v7/pkg/s3utils"
33+
"github.com/minio/minio-go/v7/pkg/tags"
3334
"golang.org/x/net/http/httpguts"
3435
)
3536

@@ -229,7 +230,9 @@ func (opts PutObjectOptions) Header() (header http.Header) {
229230
}
230231

231232
if len(opts.UserTags) != 0 {
232-
header.Set(amzTaggingHeader, s3utils.TagEncode(opts.UserTags))
233+
if tags, _ := tags.NewTags(opts.UserTags, true); tags != nil {
234+
header.Set(amzTaggingHeader, tags.String())
235+
}
233236
}
234237

235238
for k, v := range opts.UserMetadata {

Diff for: ‎pkg/s3utils/utils.go

-38
Original file line numberDiff line numberDiff line change
@@ -261,44 +261,6 @@ func QueryEncode(v url.Values) string {
261261
return buf.String()
262262
}
263263

264-
// TagDecode - decodes canonical tag into map of key and value.
265-
func TagDecode(ctag string) map[string]string {
266-
if ctag == "" {
267-
return map[string]string{}
268-
}
269-
tags := strings.Split(ctag, "&")
270-
tagMap := make(map[string]string, len(tags))
271-
var err error
272-
for _, tag := range tags {
273-
kvs := strings.SplitN(tag, "=", 2)
274-
if len(kvs) == 0 {
275-
return map[string]string{}
276-
}
277-
if len(kvs) == 1 {
278-
return map[string]string{}
279-
}
280-
tagMap[kvs[0]], err = url.PathUnescape(kvs[1])
281-
if err != nil {
282-
continue
283-
}
284-
}
285-
return tagMap
286-
}
287-
288-
// TagEncode - encodes tag values in their URL encoded form. In
289-
// addition to the percent encoding performed by urlEncodePath() used
290-
// here, it also percent encodes '/' (forward slash)
291-
func TagEncode(tags map[string]string) string {
292-
if tags == nil {
293-
return ""
294-
}
295-
values := url.Values{}
296-
for k, v := range tags {
297-
values[k] = []string{v}
298-
}
299-
return QueryEncode(values)
300-
}
301-
302264
// if object matches reserved string, no need to encode them
303265
var reservedObjectNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$")
304266

Diff for: ‎pkg/s3utils/utils_test.go

-76
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ package s3utils
2020
import (
2121
"errors"
2222
"net/url"
23-
"reflect"
2423
"testing"
2524
)
2625

@@ -298,81 +297,6 @@ func TestQueryEncode(t *testing.T) {
298297
}
299298
}
300299

301-
// Tests tag decode to map
302-
func TestTagDecode(t *testing.T) {
303-
testCases := []struct {
304-
// canonical input
305-
canonicalInput string
306-
307-
// Expected result.
308-
resultMap map[string]string
309-
}{
310-
{"k=thisisthe%25url", map[string]string{"k": "thisisthe%url"}},
311-
{"k=%E6%9C%AC%E8%AA%9E", map[string]string{"k": "本語"}},
312-
{"k=%E6%9C%AC%E8%AA%9E.1", map[string]string{"k": "本語.1"}},
313-
{"k=%3E123", map[string]string{"k": ">123"}},
314-
{"k=myurl%23link", map[string]string{"k": "myurl#link"}},
315-
{"k=space%20in%20url", map[string]string{"k": "space in url"}},
316-
{"k=url%2Bpath", map[string]string{"k": "url+path"}},
317-
{"k=url%2Fpath", map[string]string{"k": "url/path"}},
318-
}
319-
320-
for _, testCase := range testCases {
321-
testCase := testCase
322-
t.Run("", func(t *testing.T) {
323-
gotResult := TagDecode(testCase.canonicalInput)
324-
if !reflect.DeepEqual(testCase.resultMap, gotResult) {
325-
t.Errorf("Expected %s, got %s", testCase.resultMap, gotResult)
326-
}
327-
})
328-
}
329-
}
330-
331-
// Tests tag encode function for user tags.
332-
func TestTagEncode(t *testing.T) {
333-
testCases := []struct {
334-
// Input.
335-
inputMap map[string]string
336-
// Expected result.
337-
result string
338-
}{
339-
{map[string]string{
340-
"k": "thisisthe%url",
341-
}, "k=thisisthe%25url"},
342-
{map[string]string{
343-
"k": "本語",
344-
}, "k=%E6%9C%AC%E8%AA%9E"},
345-
{map[string]string{
346-
"k": "本語.1",
347-
}, "k=%E6%9C%AC%E8%AA%9E.1"},
348-
{map[string]string{
349-
"k": ">123",
350-
}, "k=%3E123"},
351-
{map[string]string{
352-
"k": "myurl#link",
353-
}, "k=myurl%23link"},
354-
{map[string]string{
355-
"k": "space in url",
356-
}, "k=space%20in%20url"},
357-
{map[string]string{
358-
"k": "url+path",
359-
}, "k=url%2Bpath"},
360-
{map[string]string{
361-
"k": "url/path",
362-
}, "k=url%2Fpath"},
363-
}
364-
365-
for _, testCase := range testCases {
366-
testCase := testCase
367-
t.Run("", func(t *testing.T) {
368-
gotResult := TagEncode(testCase.inputMap)
369-
if testCase.result != gotResult {
370-
t.Errorf("Expected %s, got %s", testCase.result, gotResult)
371-
}
372-
})
373-
}
374-
}
375-
376300
// Tests validate the URL path encoder.
377301
func TestEncodePath(t *testing.T) {
378302
testCases := []struct {

Diff for: ‎utils.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141

4242
md5simd "github.com/minio/md5-simd"
4343
"github.com/minio/minio-go/v7/pkg/s3utils"
44+
"github.com/minio/minio-go/v7/pkg/tags"
4445
)
4546

4647
func trimEtag(etag string) string {
@@ -322,7 +323,13 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
322323
userMetadata[strings.TrimPrefix(k, "X-Amz-Meta-")] = v[0]
323324
}
324325
}
325-
userTags := s3utils.TagDecode(h.Get(amzTaggingHeader))
326+
327+
userTags, err := tags.ParseObjectTags(h.Get(amzTaggingHeader))
328+
if err != nil {
329+
return ObjectInfo{}, ErrorResponse{
330+
Code: "InternalError",
331+
}
332+
}
326333

327334
var tagCount int
328335
if count := h.Get(amzTaggingCount); count != "" {
@@ -373,7 +380,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
373380
// which are not part of object metadata.
374381
Metadata: metadata,
375382
UserMetadata: userMetadata,
376-
UserTags: userTags,
383+
UserTags: userTags.ToMap(),
377384
UserTagCount: tagCount,
378385
Restore: restore,
379386

0 commit comments

Comments
 (0)
Please sign in to comment.