2018-11-09 13:54:47 +00:00
|
|
|
|
|
|
|
|
2018-11-11 16:44:30 +00:00
|
|
|
package common
|
2018-11-09 13:54:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
import "bytes"
|
|
|
|
import "fmt"
|
|
|
|
import "regexp"
|
2018-11-14 19:28:25 +00:00
|
|
|
import "sort"
|
2018-11-09 13:54:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func MetadataEncode (_metadata map[string]string) ([]byte, error) {
|
|
|
|
|
2018-11-14 19:28:25 +00:00
|
|
|
_metadataArray := make ([][2]string, 0, len (_metadata))
|
|
|
|
for _key, _value := range _metadata {
|
|
|
|
_metadataArray = append (_metadataArray, [2]string {_key, _value})
|
|
|
|
}
|
|
|
|
sort.Slice (_metadataArray,
|
|
|
|
func (i int, j int) (bool) {
|
|
|
|
return _metadataArray[i][0] < _metadataArray[j][0]
|
|
|
|
})
|
|
|
|
|
2018-11-09 13:54:47 +00:00
|
|
|
_buffer := & bytes.Buffer {}
|
|
|
|
|
2018-11-14 19:28:25 +00:00
|
|
|
for _, _metadata := range _metadataArray {
|
|
|
|
_key := _metadata[0]
|
|
|
|
_value := _metadata[1]
|
2018-11-09 13:54:47 +00:00
|
|
|
if ! metadataKeyRegex.MatchString (_key) {
|
|
|
|
return nil, fmt.Errorf ("[2f761e02] invalid metadata key: `%s`", _key)
|
|
|
|
}
|
|
|
|
if _value == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if ! metadataValueRegex.MatchString (_value) {
|
|
|
|
return nil, fmt.Errorf ("[e8faf5bd] invalid metadata value: `%s`", _value)
|
|
|
|
}
|
|
|
|
_buffer.Write ([]byte (_key))
|
|
|
|
_buffer.Write ([]byte (" : "))
|
|
|
|
_buffer.Write ([]byte (_value))
|
|
|
|
_buffer.Write ([]byte ("\n"))
|
|
|
|
}
|
|
|
|
|
|
|
|
_data := _buffer.Bytes ()
|
|
|
|
return _data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
|
2018-11-09 13:54:47 +00:00
|
|
|
func MetadataDecode (_data []byte) ([][2]string, error) {
|
|
|
|
_metadata := make ([][2]string, 0, 16)
|
2018-11-13 15:38:03 +00:00
|
|
|
_metadataAppend := func (_key []byte, _value []byte) () {
|
|
|
|
_metadata = append (_metadata, [2]string { string (_key), string (_value) })
|
|
|
|
}
|
|
|
|
if _error := MetadataDecodeIterate (_data, _metadataAppend); _error != nil {
|
|
|
|
return nil, _error
|
|
|
|
} else {
|
|
|
|
return _metadata, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func MetadataDecodeIterate (_data []byte, _callback func ([]byte, []byte) ()) (error) {
|
|
|
|
|
|
|
|
_dataSize := len (_data)
|
|
|
|
_headerOffset := 0
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
|
|
|
if _headerOffset == _dataSize {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
_data := _data[_headerOffset :]
|
|
|
|
_headerLimit := bytes.IndexByte (_data, '\n')
|
|
|
|
if (_headerLimit == -1) {
|
|
|
|
return fmt.Errorf ("[2d0d442a] invalid metadata encoding")
|
2018-11-09 13:54:47 +00:00
|
|
|
}
|
2018-11-13 15:38:03 +00:00
|
|
|
_headerOffset += _headerLimit + 1
|
|
|
|
|
|
|
|
_data = _data[: _headerLimit]
|
|
|
|
_separator := bytes.Index (_data, []byte (" : "))
|
|
|
|
if _separator == -1 {
|
|
|
|
return fmt.Errorf ("[41f3756c] invalid metadata encoding")
|
2018-11-09 13:54:47 +00:00
|
|
|
}
|
2018-11-13 15:38:03 +00:00
|
|
|
_key := _data[: _separator]
|
|
|
|
_value := _data[_separator + 3 :]
|
|
|
|
|
|
|
|
_callback (_key, _value)
|
2018-11-09 13:54:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
|
|
|
|
|
2018-11-14 17:01:08 +00:00
|
|
|
var metadataKeyRegex *regexp.Regexp = regexp.MustCompile (`\A(?:[A-Z0-9](?:[a-z0-9]?[a-z]+)(?:-[A-Z0-9](?:[a-z0-9]?[a-z]+))*)|ETag\z`)
|
2018-11-09 13:54:47 +00:00
|
|
|
var metadataValueRegex *regexp.Regexp = regexp.MustCompile (`\A[[:graph:]](?: ?[[:graph:]]+)*\z`)
|
|
|
|
|