2020-10-03 05:21:51 +00:00
|
|
|
package s3api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/xml"
|
2022-06-20 08:32:58 +00:00
|
|
|
"fmt"
|
2022-08-07 08:34:32 +00:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
2022-06-20 08:32:58 +00:00
|
|
|
"regexp"
|
2022-12-12 06:49:57 +00:00
|
|
|
"sort"
|
2022-06-20 08:32:58 +00:00
|
|
|
"strings"
|
2020-10-03 05:21:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Tag struct {
|
|
|
|
Key string `xml:"Key"`
|
|
|
|
Value string `xml:"Value"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type TagSet struct {
|
|
|
|
Tag []Tag `xml:"Tag"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Tagging struct {
|
2021-10-20 12:58:06 +00:00
|
|
|
XMLName xml.Name `xml:"Tagging"`
|
2020-10-03 05:21:51 +00:00
|
|
|
TagSet TagSet `xml:"TagSet"`
|
2021-10-20 14:12:00 +00:00
|
|
|
Xmlns string `xml:"xmlns,attr"`
|
2020-10-03 05:21:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Tagging) ToTags() map[string]string {
|
|
|
|
output := make(map[string]string)
|
|
|
|
for _, tag := range t.TagSet.Tag {
|
|
|
|
output[tag.Key] = tag.Value
|
|
|
|
}
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
func FromTags(tags map[string]string) (t *Tagging) {
|
2021-10-20 14:40:22 +00:00
|
|
|
t = &Tagging{Xmlns: "http://s3.amazonaws.com/doc/2006-03-01/"}
|
2020-10-03 05:21:51 +00:00
|
|
|
for k, v := range tags {
|
|
|
|
t.TagSet.Tag = append(t.TagSet.Tag, Tag{
|
|
|
|
Key: k,
|
|
|
|
Value: v,
|
|
|
|
})
|
|
|
|
}
|
2022-12-12 06:49:57 +00:00
|
|
|
if tagArr := t.TagSet.Tag; len(tagArr) > 0 {
|
|
|
|
sort.SliceStable(tagArr, func(i, j int) bool {
|
|
|
|
return tagArr[i].Key < tagArr[j].Key
|
|
|
|
})
|
|
|
|
}
|
2020-10-03 05:21:51 +00:00
|
|
|
return
|
|
|
|
}
|
2022-06-20 08:32:58 +00:00
|
|
|
|
|
|
|
func parseTagsHeader(tags string) (map[string]string, error) {
|
2022-06-27 15:46:21 +00:00
|
|
|
parsedTags := make(map[string]string)
|
2022-08-07 08:34:32 +00:00
|
|
|
for _, v := range util.StringSplit(tags, "&") {
|
2022-06-20 08:32:58 +00:00
|
|
|
tag := strings.Split(v, "=")
|
|
|
|
if len(tag) == 2 {
|
|
|
|
parsedTags[tag[0]] = tag[1]
|
|
|
|
} else if len(tag) == 1 {
|
|
|
|
parsedTags[tag[0]] = ""
|
|
|
|
}
|
|
|
|
}
|
2022-06-27 15:46:21 +00:00
|
|
|
return parsedTags, nil
|
2022-06-20 08:32:58 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 11:48:55 +00:00
|
|
|
func ValidateTags(tags map[string]string) error {
|
2022-06-20 08:32:58 +00:00
|
|
|
if len(tags) > 10 {
|
|
|
|
return fmt.Errorf("validate tags: %d tags more than 10", len(tags))
|
|
|
|
}
|
|
|
|
for k, v := range tags {
|
|
|
|
if len(k) > 128 {
|
2022-06-28 11:48:55 +00:00
|
|
|
return fmt.Errorf("validate tags: tag key longer than 128")
|
2022-06-20 08:32:58 +00:00
|
|
|
}
|
|
|
|
validateKey, err := regexp.MatchString(`^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$`, k)
|
2022-06-28 11:48:55 +00:00
|
|
|
if !validateKey || err != nil {
|
|
|
|
return fmt.Errorf("validate tags key %s error, incorrect key", k)
|
2022-06-20 08:32:58 +00:00
|
|
|
}
|
|
|
|
if len(v) > 256 {
|
2022-06-28 11:48:55 +00:00
|
|
|
return fmt.Errorf("validate tags: tag value longer than 256")
|
2022-06-20 08:32:58 +00:00
|
|
|
}
|
|
|
|
validateValue, err := regexp.MatchString(`^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$`, v)
|
2022-06-28 11:48:55 +00:00
|
|
|
if !validateValue || err != nil {
|
|
|
|
return fmt.Errorf("validate tags value %s error, incorrect value", v)
|
2022-06-20 08:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|