Skip to content

Commit

Permalink
Support SetEscapeHTML
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy committed May 3, 2020
1 parent 3d7267a commit 6602d2d
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 98 deletions.
4 changes: 3 additions & 1 deletion benchmarks/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ go 1.12

require (
github.com/francoispqt/gojay v1.2.13
github.com/goccy/go-json v0.0.0-20200430045642-6a479c7159bf
github.com/goccy/go-json v0.0.0-00010101000000-000000000000
github.com/json-iterator/go v1.1.9
github.com/mailru/easyjson v0.7.1
)

replace github.com/goccy/go-json => ../
10 changes: 0 additions & 10 deletions benchmarks/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/goccy/go-json v0.0.0-20200425134937-b2f2a20f6518 h1:Im9WLti1rM0Lu7yfI7Q4qUa63ACa8MpcWsKsP/s1scI=
github.com/goccy/go-json v0.0.0-20200425134937-b2f2a20f6518/go.mod h1:h37TlF6fMJkCKBvuOxM3yCc3CnzMOUL3Ya+zO4ERYXQ=
github.com/goccy/go-json v0.0.0-20200426030317-c37a3c1aac7b h1:x2rU3NmJ9v14sP8q6ibSDHWm3dAmEvVPjxiLAAz4iU0=
github.com/goccy/go-json v0.0.0-20200426030317-c37a3c1aac7b/go.mod h1:R/y4ycIiFvB+n4HQ2M0/BzGzFxFvgGk5wwIp4Q2JkCk=
github.com/goccy/go-json v0.0.0-20200426055945-3bd7507c309f h1:ZIUfVwBw7xpFIPp/7neJMAycPOv1HEbLsloc2FF6/mY=
github.com/goccy/go-json v0.0.0-20200426055945-3bd7507c309f/go.mod h1:R/y4ycIiFvB+n4HQ2M0/BzGzFxFvgGk5wwIp4Q2JkCk=
github.com/goccy/go-json v0.0.0-20200426062255-9b1349d40ab6 h1:vJLqMycJ1FZ5RAtM5uU2beB/1cw8CqhY/LQAsffUDTU=
github.com/goccy/go-json v0.0.0-20200426062255-9b1349d40ab6/go.mod h1:R/y4ycIiFvB+n4HQ2M0/BzGzFxFvgGk5wwIp4Q2JkCk=
github.com/goccy/go-json v0.0.0-20200430045642-6a479c7159bf h1:mnwIPeyuqSC+ADJsNaMkl3vlQc09zpHDzwNK83ftk9g=
github.com/goccy/go-json v0.0.0-20200430045642-6a479c7159bf/go.mod h1:R/y4ycIiFvB+n4HQ2M0/BzGzFxFvgGk5wwIp4Q2JkCk=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
Expand Down
32 changes: 21 additions & 11 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import (

// An Encoder writes JSON values to an output stream.
type Encoder struct {
w io.Writer
buf []byte
pool sync.Pool
enabledIndent bool
prefix []byte
indentStr []byte
indent int
w io.Writer
buf []byte
pool sync.Pool
enabledIndent bool
enabledHTMLEscape bool
prefix []byte
indentStr []byte
indent int
}

const (
Expand Down Expand Up @@ -65,7 +66,6 @@ func init() {
func NewEncoder(w io.Writer) *Encoder {
enc := encPool.Get().(*Encoder)
enc.w = w
enc.indent = 0
enc.reset()
return enc
}
Expand All @@ -88,7 +88,7 @@ func (e *Encoder) Encode(v interface{}) error {
//
// In non-HTML settings where the escaping interferes with the readability of the output, SetEscapeHTML(false) disables this behavior.
func (e *Encoder) SetEscapeHTML(on bool) {

e.enabledHTMLEscape = on
}

// SetIndent instructs the encoder to format each subsequent encoded value as if indented by the package-level function Indent(dst, src, prefix, indent).
Expand All @@ -110,6 +110,9 @@ func (e *Encoder) release() {

func (e *Encoder) reset() {
e.buf = e.buf[:0]
e.indent = 0
e.enabledHTMLEscape = true
e.enabledIndent = false
}

func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
Expand Down Expand Up @@ -225,9 +228,16 @@ func (e *Encoder) encodeBytes(b []byte) {
e.buf = append(e.buf, b...)
}

func (e *Encoder) encodeNull() {
e.buf = append(e.buf, 'n', 'u', 'l', 'l')
}

func (e *Encoder) encodeString(s string) {
b := *(*[]byte)(unsafe.Pointer(&s))
e.buf = append(e.buf, b...)
if e.enabledHTMLEscape {
e.encodeEscapedString(s)
} else {
e.encodeNoEscapedString(s)
}
}

func (e *Encoder) encodeByte(b byte) {
Expand Down
64 changes: 64 additions & 0 deletions encode_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,67 @@ func (e *Encoder) writeStringSlowPathWithHTMLEscaped(i int, s string, valLen int
}
e.buf = append(e.buf, '"')
}

func (e *Encoder) encodeNoEscapedString(s string) {
valLen := len(s)
e.buf = append(e.buf, '"')

// write string, the fast path, without utf8 and escape support
i := 0
for ; i < valLen; i++ {
c := s[i]
if c > 31 && c != '"' && c != '\\' {
e.buf = append(e.buf, c)
} else {
break
}
}
if i == valLen {
e.buf = append(e.buf, '"')
return
}
e.writeStringSlowPath(i, s, valLen)
}

func (e *Encoder) writeStringSlowPath(i int, s string, valLen int) {
start := i
// for the remaining parts, we process them char by char
for i < valLen {
if b := s[i]; b < utf8.RuneSelf {
if safeSet[b] {
i++
continue
}
if start < i {
e.buf = append(e.buf, s[start:i]...)
}
switch b {
case '\\', '"':
e.buf = append(e.buf, '\\', b)
case '\n':
e.buf = append(e.buf, '\\', 'n')
case '\r':
e.buf = append(e.buf, '\\', 'r')
case '\t':
e.buf = append(e.buf, '\\', 't')
default:
// This encodes bytes < 0x20 except for \t, \n and \r.
// If escapeHTML is set, it also escapes <, >, and &
// because they can lead to security holes when
// user-controlled strings are rendered into JSON
// and served to some browsers.
e.buf = append(e.buf, []byte(`\u00`)...)
e.buf = append(e.buf, hex[b>>4], hex[b&0xF])
}
i++
start = i
continue
}
i++
continue
}
if start < len(s) {
e.buf = append(e.buf, s[start:]...)
}
e.buf = append(e.buf, '"')
}
Loading

0 comments on commit 6602d2d

Please sign in to comment.