Update string handling

Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>
pull/10336/merge
Martin Hickey 2 years ago
parent 3974136b6e
commit a59e584684

@ -36,6 +36,10 @@ var ErrNotList = errors.New("not a list")
// The default value 65536 = 1024 * 64
var MaxIndex = 65536
// MaxNestedNameLevel is the maximum level of nesting for a value name that
// will be allowed.
var MaxNestedNameLevel = 30
// ToYAML takes a string of arguments and converts to a YAML document.
func ToYAML(s string) (string, error) {
m, err := Parse(s)
@ -155,7 +159,7 @@ func newFileParser(sc *bytes.Buffer, data map[string]interface{}, reader RunesVa
func (t *parser) parse() error {
for {
err := t.key(t.data)
err := t.key(t.data, 0)
if err == nil {
continue
}
@ -174,7 +178,7 @@ func runeSet(r []rune) map[rune]bool {
return s
}
func (t *parser) key(data map[string]interface{}) (reterr error) {
func (t *parser) key(data map[string]interface{}, nestedNameLevel int) (reterr error) {
defer func() {
if r := recover(); r != nil {
reterr = fmt.Errorf("unable to parse key: %s", r)
@ -204,7 +208,7 @@ func (t *parser) key(data map[string]interface{}) (reterr error) {
}
// Now we need to get the value after the ].
list, err = t.listItem(list, i)
list, err = t.listItem(list, i, nestedNameLevel)
set(data, kk, list)
return err
case last == '=':
@ -261,6 +265,12 @@ func (t *parser) key(data map[string]interface{}) (reterr error) {
set(data, string(k), "")
return errors.Errorf("key %q has no value (cannot end with ,)", string(k))
case last == '.':
// Check value name is within the maximum nested name level
nestedNameLevel++
if nestedNameLevel > MaxNestedNameLevel {
return fmt.Errorf("value name nested level is greater than maximum supported nested level of %d", MaxNestedNameLevel)
}
// First, create or find the target map.
inner := map[string]interface{}{}
if _, ok := data[string(k)]; ok {
@ -268,12 +278,14 @@ func (t *parser) key(data map[string]interface{}) (reterr error) {
}
// Recurse
e := t.key(inner)
if e := t.key(inner, nestedNameLevel); e != nil {
return e
}
if len(inner) == 0 {
return errors.Errorf("key map %q has no value", string(k))
}
set(data, string(k), inner)
return e
return nil
}
}
}
@ -322,7 +334,7 @@ func (t *parser) keyIndex() (int, error) {
return strconv.Atoi(string(v))
}
func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
func (t *parser) listItem(list []interface{}, i, nestedNameLevel int) ([]interface{}, error) {
if i < 0 {
return list, fmt.Errorf("negative %d index not allowed", i)
}
@ -395,7 +407,7 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
}
}
// Now we need to get the value after the ].
list2, err := t.listItem(crtList, nextI)
list2, err := t.listItem(crtList, nextI, nestedNameLevel)
if err != nil {
return list, err
}
@ -414,7 +426,7 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
}
// Recurse
e := t.key(inner)
e := t.key(inner, nestedNameLevel)
if e != nil {
return list, e
}

@ -16,6 +16,7 @@ limitations under the License.
package strvals
import (
"fmt"
"testing"
"sigs.k8s.io/yaml"
@ -247,8 +248,9 @@ func TestParseSet(t *testing.T) {
err: true,
},
{
str: "name1.name2=",
expect: map[string]interface{}{"name1": map[string]interface{}{"name2": ""}},
"name1.name2=",
map[string]interface{}{},
false,
},
{
str: "name1.=name2",
@ -754,3 +756,55 @@ func TestToYAML(t *testing.T) {
t.Errorf("Expected %q, got %q", expect, o)
}
}
func TestParseSetNestedLevels(t *testing.T) {
var keyMultipleNestedLevels string
for i := 1; i <= MaxNestedNameLevel+2; i++ {
tmpStr := fmt.Sprintf("name%d", i)
if i <= MaxNestedNameLevel+1 {
tmpStr = tmpStr + "."
}
keyMultipleNestedLevels += tmpStr
}
tests := []struct {
str string
expect map[string]interface{}
err bool
}{
{
"outer.middle.inner=value",
map[string]interface{}{"outer": map[string]interface{}{"middle": map[string]interface{}{"inner": "value"}}},
false,
},
{
str: keyMultipleNestedLevels + "=value",
err: true,
},
}
for _, tt := range tests {
got, err := Parse(tt.str)
if err != nil {
if tt.err {
continue
}
t.Fatalf("%s: %s", tt.str, err)
}
if tt.err {
t.Errorf("%s: Expected error. Got nil", tt.str)
}
y1, err := yaml.Marshal(tt.expect)
if err != nil {
t.Fatal(err)
}
y2, err := yaml.Marshal(got)
if err != nil {
t.Fatalf("Error serializing parsed value: %s", err)
}
if string(y1) != string(y2) {
t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2)
}
}
}

Loading…
Cancel
Save