Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix metadata parsing #1953

Merged
merged 4 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 52 additions & 9 deletions common/fe-ste-models.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package common
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"os"
Expand Down Expand Up @@ -674,9 +675,11 @@ type TransferStatus int32 // Must be 32-bit for atomic operations; negative #s r
func (TransferStatus) NotStarted() TransferStatus { return TransferStatus(0) }

// TODO confirm whether this is actually needed
// Outdated:
// Transfer started & at least 1 chunk has successfully been transferred.
// Used to resume a transfer that started to avoid transferring all chunks thereby improving performance
//
// Outdated:
// Transfer started & at least 1 chunk has successfully been transferred.
// Used to resume a transfer that started to avoid transferring all chunks thereby improving performance
//
// Update(Jul 2020): This represents the state of transfer as soon as the file is scheduled.
func (TransferStatus) Started() TransferStatus { return TransferStatus(1) }

Expand Down Expand Up @@ -1075,13 +1078,53 @@ func UnMarshalToCommonMetadata(metadataString string) (Metadata, error) {
func StringToMetadata(metadataString string) (Metadata, error) {
metadataMap := Metadata{}
if len(metadataString) > 0 {
for _, keyAndValue := range strings.Split(metadataString, ";") { // key/value pairs are separated by ';'
kv := strings.Split(keyAndValue, "=") // key/value are separated by '='
// what if '=' not present?
if len(kv) != 2 {
return metadataMap, fmt.Errorf("invalid metadata string passed")
cKey := ""
cVal := ""
keySet := false
ignoreRules := false

addchar := func(c rune) {
if !keySet {
cKey += string(c)
} else {
cVal += string(c)
}
}
for _, c := range metadataString {
if ignoreRules {
addchar(c)
ignoreRules = false
} else {
switch c {
case '=':
if keySet {
addchar(c)
} else {
keySet = true
}

case ';':
if !keySet {
return Metadata{}, errors.New("metadata names must conform to C# naming rules (https://learn.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#metadata-names)")
}

metadataMap[cKey] = cVal
cKey = ""
cVal = ""
keySet = false
ignoreRules = false

case '\\':
ignoreRules = true // ignore the rules on the next character

default:
addchar(c)
}
}
metadataMap[kv[0]] = kv[1]
}

if cKey != "" {
metadataMap[cKey] = cVal
}
}
return metadataMap, nil
Expand Down
4 changes: 2 additions & 2 deletions e2etest/zt_preserve_properties_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ func TestProperties_NameValueMetadataIsPreservedS2S(t *testing.T) {
}

func TestProperties_NameValueMetadataCanBeUploaded(t *testing.T) {
expectedMap := map[string]string{"foo": "abc", "bar": "def"}
expectedMap := map[string]string{"foo": "abc", "bar": "def", "baz": "te=s;t"}
RunScenarios(t, eOperation.Copy(), eTestFromTo.AllUploads(), eValidate.Auto(), anonymousAuthOnly, anonymousAuthOnly, params{
recursive: true,
metadata: "foo=abc;bar=def",
metadata: "foo=abc;bar=def;baz=te=s\\;t",
}, nil, testFiles{
defaultSize: "1K",
shouldTransfer: []interface{}{
Expand Down
7 changes: 4 additions & 3 deletions ste/mgr-JobPartMgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,10 @@ func (jpm *jobPartMgr) ScheduleTransfers(jobCtx context.Context) {
metadataString := string(dstData.Metadata[:dstData.MetadataLength])
jpm.metadata = common.Metadata{}
if len(metadataString) > 0 {
for _, keyAndValue := range strings.Split(metadataString, ";") { // key/value pairs are separated by ';'
kv := strings.Split(keyAndValue, "=") // key/value are separated by '='
jpm.metadata[kv[0]] = kv[1]
var err error
jpm.metadata, err = common.StringToMetadata(metadataString)
if err != nil {
panic("sanity check: metadata string should be valid at this point: " + metadataString)
}
}
blobTagsStr := string(dstData.BlobTags[:dstData.BlobTagsLength])
Expand Down