From b03586904129ea424c7753ff9dfca256c9218b48 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. --- CHANGELOG_PENDING.md | 1 + private/protocol/xml/xmlutil/build.go | 2 ++ private/protocol/xml/xmlutil/build_test.go | 6 +++++ private/protocol/xml/xmlutil/xml_to_struct.go | 22 +++++++++++++++---- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 8a1927a39c..518875deb1 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,5 +1,6 @@ ### SDK Features ### SDK Enhancements +* `private/protocol/xml/xmlutil`: XML encoding has been updated to include encoding line feed character. ([#3881](https://github.com/aws/aws-sdk-go/pull/3881)) ### SDK Bugs diff --git a/private/protocol/xml/xmlutil/build.go b/private/protocol/xml/xmlutil/build.go index 09ad951595..2fbb93ae76 100644 --- a/private/protocol/xml/xmlutil/build.go +++ b/private/protocol/xml/xmlutil/build.go @@ -308,6 +308,8 @@ func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag refl if tag.Get("xmlAttribute") != "" { // put into current node's attribute list attr := xml.Attr{Name: xname, Value: str} current.Attr = append(current.Attr, attr) + } else if len(xname.Local) == 0 { + current.Text = str } else { // regular text node current.AddChild(&XMLNode{Name: xname, Text: str}) } diff --git a/private/protocol/xml/xmlutil/build_test.go b/private/protocol/xml/xmlutil/build_test.go index 0ab5b6866e..a50900c857 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 42f71648ee..c85b79fddd 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() ([]byte, 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,11 +138,16 @@ 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 { + e.EncodeElement(textEncoder(node.Text), startElement) + return e.Flush() + } + + e.EncodeToken(startElement) + + if sorted { sortedNames := []string{} for k := range node.Children { sortedNames = append(sortedNames, k) @@ -154,6 +167,7 @@ func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error { } } - e.EncodeToken(xml.EndElement{Name: node.Name}) + e.EncodeToken(startElement.End()) + return e.Flush() }