From e2224a69f98c8fdc9c4a9328cbf749b9bd9358a7 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Mon, 26 Apr 2021 14:31:10 -0700 Subject: [PATCH] private/protocol/xml/xmlutil: Updated XML encoding to ensure line feed is escaped. --- private/protocol/xml/xmlutil/build_test.go | 6 +++ private/protocol/xml/xmlutil/xml_to_struct.go | 47 ++++++++++++------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/private/protocol/xml/xmlutil/build_test.go b/private/protocol/xml/xmlutil/build_test.go index 0ab5b6866e5..a50900c857a 100644 --- a/private/protocol/xml/xmlutil/build_test.go +++ b/private/protocol/xml/xmlutil/build_test.go @@ -153,6 +153,12 @@ func TestBuildXML(t *testing.T) { Input: &namedEmptyPayload{}, Expect: "", }, + "escape line feed and carriage return": { + Input: &implicitPayload{ + StrVal: aws.String("this\nstring\rhas\r\nescapable\n\rcharacters"), + }, + Expect: "this string has escapable characters", + }, } for name, c := range cases { diff --git a/private/protocol/xml/xmlutil/xml_to_struct.go b/private/protocol/xml/xmlutil/xml_to_struct.go index 42f71648eee..2cf112a7e88 100644 --- a/private/protocol/xml/xmlutil/xml_to_struct.go +++ b/private/protocol/xml/xmlutil/xml_to_struct.go @@ -18,6 +18,14 @@ type XMLNode struct { parent *XMLNode } +// textEncoder is a string type alias that implemnts the TextMarshaler interface. +// This alias type is used to ensure that the line feed (\n) (U+000A) is escaped. +type textEncoder string + +func (t textEncoder) MarshalText() (text []byte, err error) { + return []byte(t), nil +} + // NewXMLElement returns a pointer to a new XMLNode initialized to default values. func NewXMLElement(name xml.Name) *XMLNode { return &XMLNode{ @@ -130,30 +138,35 @@ func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error { attrs = sortedAttrs } - e.EncodeToken(xml.StartElement{Name: node.Name, Attr: attrs}) + startElement := xml.StartElement{Name: node.Name, Attr: attrs} if node.Text != "" { - e.EncodeToken(xml.CharData([]byte(node.Text))) - } else if sorted { - sortedNames := []string{} - for k := range node.Children { - sortedNames = append(sortedNames, k) - } - sort.Strings(sortedNames) + e.EncodeElement(textEncoder(node.Text), startElement) + } else { + e.EncodeToken(startElement) - for _, k := range sortedNames { - for _, v := range node.Children[k] { - StructToXML(e, v, sorted) + if sorted { + sortedNames := []string{} + for k := range node.Children { + sortedNames = append(sortedNames, k) } - } - } else { - for _, c := range node.Children { - for _, v := range c { - StructToXML(e, v, sorted) + sort.Strings(sortedNames) + + for _, k := range sortedNames { + for _, v := range node.Children[k] { + StructToXML(e, v, sorted) + } + } + } else { + for _, c := range node.Children { + for _, v := range c { + StructToXML(e, v, sorted) + } } } + + e.EncodeToken(xml.EndElement{Name: node.Name}) } - e.EncodeToken(xml.EndElement{Name: node.Name}) return e.Flush() }