aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2023-02-20 00:42:27 -0800
committerGopher Robot <gobot@golang.org>2023-02-27 17:33:26 +0000
commit2de406bb9e26df19a31b5f6111bb221b60964d48 (patch)
tree024c7be050abfaa8ab8276b9ffac0445b927c9a9 /src
parent0b5affb193ed559f2cb646e0324827f261e2e767 (diff)
downloadgo-2de406bb9e26df19a31b5f6111bb221b60964d48.tar.xz
encoding/json: use append for HTMLEscape
Use append for HTMLEscape similar to Indent and Compact. Move it to indent.go alongside Compact, as it shares similar logic. In a future CL, we will modify appendCompact to be written in terms of appendHTMLEscape, but we need to first move the JSON decoder logic out of the main loop of appendCompact. Change-Id: I131c64cd53d5d2b4ca798b37349aeefe17b418c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/471198 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Run-TryBot: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com> Auto-Submit: Joseph Tsai <joetsai@digital-static.net>
Diffstat (limited to 'src')
-rw-r--r--src/encoding/json/encode.go46
-rw-r--r--src/encoding/json/indent.go30
2 files changed, 34 insertions, 42 deletions
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index ff0e40d532..de639aa008 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -183,41 +183,6 @@ func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
return b2, nil
}
-// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
-// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
-// so that the JSON will be safe to embed inside HTML <script> tags.
-// For historical reasons, web browsers don't honor standard HTML
-// escaping within <script> tags, so an alternative JSON encoding must
-// be used.
-func HTMLEscape(dst *bytes.Buffer, src []byte) {
- // The characters can only appear in string literals,
- // so just scan the string one byte at a time.
- start := 0
- for i, c := range src {
- if c == '<' || c == '>' || c == '&' {
- if start < i {
- dst.Write(src[start:i])
- }
- dst.WriteString(`\u00`)
- dst.WriteByte(hex[c>>4])
- dst.WriteByte(hex[c&0xF])
- start = i + 1
- }
- // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
- if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
- if start < i {
- dst.Write(src[start:i])
- }
- dst.WriteString(`\u202`)
- dst.WriteByte(hex[src[i+2]&0xF])
- start = i + 3
- }
- }
- if start < len(src) {
- dst.Write(src[start:])
- }
-}
-
// Marshaler is the interface implemented by types that
// can marshal themselves into valid JSON.
type Marshaler interface {
@@ -1119,8 +1084,8 @@ func typeFields(t reflect.Type) structFields {
// Fields found.
var fields []field
- // Buffer to run HTMLEscape on field names.
- var nameEscBuf bytes.Buffer
+ // Buffer to run appendHTMLEscape on field names.
+ var nameEscBuf []byte
for len(next) > 0 {
current, next = next, current[:0]
@@ -1199,11 +1164,8 @@ func typeFields(t reflect.Type) structFields {
field.equalFold = foldFunc(field.nameBytes)
// Build nameEscHTML and nameNonEsc ahead of time.
- nameEscBuf.Reset()
- nameEscBuf.WriteString(`"`)
- HTMLEscape(&nameEscBuf, field.nameBytes)
- nameEscBuf.WriteString(`":`)
- field.nameEscHTML = nameEscBuf.String()
+ nameEscBuf = appendHTMLEscape(nameEscBuf[:0], field.nameBytes)
+ field.nameEscHTML = `"` + string(nameEscBuf) + `":`
field.nameNonEsc = `"` + field.name + `":`
fields = append(fields, field)
diff --git a/src/encoding/json/indent.go b/src/encoding/json/indent.go
index 375f71605a..99951208a0 100644
--- a/src/encoding/json/indent.go
+++ b/src/encoding/json/indent.go
@@ -11,6 +11,36 @@ func availableBuffer(b *bytes.Buffer) []byte {
return b.Bytes()[b.Len():]
}
+// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
+// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
+// so that the JSON will be safe to embed inside HTML <script> tags.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+ dst.Grow(len(src))
+ dst.Write(appendHTMLEscape(availableBuffer(dst), src))
+}
+
+func appendHTMLEscape(dst, src []byte) []byte {
+ // The characters can only appear in string literals,
+ // so just scan the string one byte at a time.
+ start := 0
+ for i, c := range src {
+ if c == '<' || c == '>' || c == '&' {
+ dst = append(dst, src[start:i]...)
+ dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF])
+ start = i + 1
+ }
+ // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
+ if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
+ dst = append(dst, src[start:i]...)
+ dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF])
+ start = i + len("\u2029")
+ }
+ }
+ return append(dst, src[start:]...)
+}
+
// Compact appends to dst the JSON-encoded src with
// insignificant space characters elided.
func Compact(dst *bytes.Buffer, src []byte) error {