Skip to content

Commit

Permalink
encoding/json: obey SetEscapeHTML in all MarshalJSON cases
Browse files Browse the repository at this point in the history
It wasn't obeyed in the case where the MarshalJSON method uses a pointer
receiver, and the encoder grabs the address of a value to find that
method. addrMarshalerEncoder is the function that does this work, but it
ignored opts.escapeHTML.

Here's the before and after of the added test case, which was failing
before the fix. Now the two cases are correct and consistent.

	{"NonPtr":"<str>","Ptr":"\u003cstr\u003e"}
	{"NonPtr":"<str>","Ptr":"<str>"}

Fixes #32896.

Change-Id: Idc53077ece074973558bd3bb5ad036380db0d02c
Reviewed-on: https://go-review.googlesource.com/c/go/+/184757
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Caleb Spare <cespare@gmail.com>
  • Loading branch information
mvdan committed Jul 6, 2019
1 parent 721c629 commit 1108d26
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 2 deletions.
4 changes: 2 additions & 2 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
}
}

func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
va := v.Addr()
if va.IsNil() {
e.WriteString("null")
Expand All @@ -470,7 +470,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
b, err := m.MarshalJSON()
if err == nil {
// copy JSON into buffer, checking validity.
err = compact(&e.Buffer, b, true)
err = compact(&e.Buffer, b, opts.escapeHTML)
}
if err != nil {
e.error(&MarshalerError{v.Type(), err})
Expand Down
26 changes: 26 additions & 0 deletions stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,34 @@ func TestEncoderIndent(t *testing.T) {
}
}

type strMarshaler string

func (s strMarshaler) MarshalJSON() ([]byte, error) {
return []byte(s), nil
}

type strPtrMarshaler string

func (s *strPtrMarshaler) MarshalJSON() ([]byte, error) {
return []byte(*s), nil
}

func TestEncoderSetEscapeHTML(t *testing.T) {
var c C
var ct CText
var tagStruct struct {
Valid int `json:"<>&#! "`
Invalid int `json:"\\"`
}

// This case is particularly interesting, as we force the encoder to
// take the address of the Ptr field to use its MarshalJSON method. This
// is why the '&' is important.
marshalerStruct := &struct {
NonPtr strMarshaler
Ptr strPtrMarshaler
}{`"<str>"`, `"<str>"`}

for _, tt := range []struct {
name string
v interface{}
Expand All @@ -111,6 +132,11 @@ func TestEncoderSetEscapeHTML(t *testing.T) {
`{"\u003c\u003e\u0026#! ":0,"Invalid":0}`,
`{"<>&#! ":0,"Invalid":0}`,
},
{
`"<str>"`, marshalerStruct,
`{"NonPtr":"\u003cstr\u003e","Ptr":"\u003cstr\u003e"}`,
`{"NonPtr":"<str>","Ptr":"<str>"}`,
},
} {
var buf bytes.Buffer
enc := NewEncoder(&buf)
Expand Down

0 comments on commit 1108d26

Please sign in to comment.