Skip to content

Commit 88045f2

Browse files
author
Kz Ho
committed
Combine Stream.WriteString's slow path into one with escapeHTML bool flag
- refer to https://go.dev/src/encoding/json/encode.go#L1029
1 parent de82dbd commit 88045f2

File tree

1 file changed

+24
-67
lines changed

1 file changed

+24
-67
lines changed

stream_str.go

+24-67
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,36 @@ func (stream *Stream) WriteStringWithHTMLEscaped(s string) {
235235
stream.buf = append(stream.buf, '"')
236236
return
237237
}
238-
writeStringSlowPathWithHTMLEscaped(stream, i, s, valLen)
238+
writeStringSlowPath(stream, i, s, valLen, true)
239239
}
240240

241-
func writeStringSlowPathWithHTMLEscaped(stream *Stream, i int, s string, valLen int) {
241+
// WriteString write string to stream without html escape
242+
func (stream *Stream) WriteString(s string) {
243+
valLen := len(s)
244+
stream.buf = append(stream.buf, '"')
245+
// write string, the fast path, without utf8 and escape support
246+
i := 0
247+
for ; i < valLen; i++ {
248+
c := s[i]
249+
if c < utf8.RuneSelf && safeSet[c] {
250+
stream.buf = append(stream.buf, c)
251+
} else {
252+
break
253+
}
254+
}
255+
if i == valLen {
256+
stream.buf = append(stream.buf, '"')
257+
return
258+
}
259+
writeStringSlowPath(stream, i, s, valLen, false)
260+
}
261+
262+
func writeStringSlowPath(stream *Stream, i int, s string, valLen int, escapeHTML bool) {
242263
start := i
243264
// for the remaining parts, we process them char by char
244265
for i < valLen {
245266
if b := s[i]; b < utf8.RuneSelf {
246-
if htmlSafeSet[b] {
267+
if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
247268
i++
248269
continue
249270
}
@@ -306,67 +327,3 @@ func writeStringSlowPathWithHTMLEscaped(stream *Stream, i int, s string, valLen
306327
}
307328
stream.writeByte('"')
308329
}
309-
310-
// WriteString write string to stream without html escape
311-
func (stream *Stream) WriteString(s string) {
312-
valLen := len(s)
313-
stream.buf = append(stream.buf, '"')
314-
// write string, the fast path, without utf8 and escape support
315-
i := 0
316-
for ; i < valLen; i++ {
317-
c := s[i]
318-
if c < utf8.RuneSelf && safeSet[c] {
319-
stream.buf = append(stream.buf, c)
320-
} else {
321-
break
322-
}
323-
}
324-
if i == valLen {
325-
stream.buf = append(stream.buf, '"')
326-
return
327-
}
328-
writeStringSlowPath(stream, i, s, valLen)
329-
}
330-
331-
func writeStringSlowPath(stream *Stream, i int, s string, valLen int) {
332-
start := i
333-
// for the remaining parts, we process them char by char
334-
for i < valLen {
335-
if b := s[i]; b < utf8.RuneSelf {
336-
if safeSet[b] {
337-
i++
338-
continue
339-
}
340-
if start < i {
341-
stream.WriteRaw(s[start:i])
342-
}
343-
switch b {
344-
case '\\', '"':
345-
stream.writeTwoBytes('\\', b)
346-
case '\n':
347-
stream.writeTwoBytes('\\', 'n')
348-
case '\r':
349-
stream.writeTwoBytes('\\', 'r')
350-
case '\t':
351-
stream.writeTwoBytes('\\', 't')
352-
default:
353-
// This encodes bytes < 0x20 except for \t, \n and \r.
354-
// If escapeHTML is set, it also escapes <, >, and &
355-
// because they can lead to security holes when
356-
// user-controlled strings are rendered into JSON
357-
// and served to some browsers.
358-
stream.WriteRaw(`\u00`)
359-
stream.writeTwoBytes(hex[b>>4], hex[b&0xF])
360-
}
361-
i++
362-
start = i
363-
continue
364-
}
365-
i++
366-
continue
367-
}
368-
if start < len(s) {
369-
stream.WriteRaw(s[start:])
370-
}
371-
stream.writeByte('"')
372-
}

0 commit comments

Comments
 (0)