encoding/xml: normalize \t, \r and \n to space in attributes

This is required by the spec.

Fixes: #20614
This commit is contained in:
Demi Marie Obenour 2024-07-14 15:00:06 -04:00 committed by Demi Marie Obenour
parent 3fd729b2a1
commit a7e1f3b706
3 changed files with 39 additions and 3 deletions

View File

@ -602,6 +602,12 @@ var marshalTests = []struct {
ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
UnmarshalOnly: true,
},
// Check attribute value normalization (issue 20614).
{
Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte(" a b c d")},
ExpectXML: "<Data Attr='\na\r\nb\tc\rd'><Bytes></Bytes><Custom></Custom></Data>",
UnmarshalOnly: true,
},
// Check that []byte works, including named []byte types.
{

View File

@ -1119,11 +1119,17 @@ Input:
return nil
}
// We must rewrite unescaped \r and \r\n into \n.
if b == '\r' {
d.buf.WriteByte('\n')
// We must rewrite unescaped \r and \r\n into \n outside quotes,
// and unescaped \r, \r\n, \n, and \t into space inside quotes.
if b >= ' ' {
d.buf.WriteByte(b)
} else if b1 == '\r' && b == '\n' {
// Skip \r\n--we already wrote \n.
} else if quote >= 0 && (b == '\r' || b == '\n' || b == '\t') {
// Normalize newline, CR, and tab into space
d.buf.WriteByte(' ')
} else if b == '\r' {
d.buf.WriteByte('\n')
} else {
d.buf.WriteByte(b)
}

View File

@ -650,6 +650,30 @@ func TestIssue68387(t *testing.T) {
}
}
func TestIssue20614(t *testing.T) {
data := "<item b='\n\r\t'/>"
dec := NewDecoder(strings.NewReader(data))
var tok1, tok2, tok3 Token
var err error
if tok1, err = dec.RawToken(); err != nil {
t.Fatalf("RawToken() failed: %#v", err)
}
if tok2, err = dec.RawToken(); err != nil {
t.Fatalf("RawToken() failed: %#v", err)
}
if tok3, err = dec.RawToken(); err != io.EOF || tok3 != nil {
t.Fatalf("Missed EOF")
}
s := StartElement{Name{"", "item"}, []Attr{Attr{Name{"","b"}, " "}}}
if !reflect.DeepEqual(tok1.(StartElement), s) {
t.Error("Wrong start element")
}
e := EndElement{Name{"","item"}}
if tok2.(EndElement) != e {
t.Error("Wrong end element")
}
}
func TestIssue569(t *testing.T) {
data := `<item><FieldA>abcd</FieldA></item>`
var i item