From de82dbdcc7e537031317b33b5f7b0c4dbf3e364f Mon Sep 17 00:00:00 2001 From: Kz Ho Date: Thu, 9 Mar 2023 12:28:11 +0800 Subject: [PATCH 1/2] Fix Stream.WriteString's fast path condition --- stream_str.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stream_str.go b/stream_str.go index 54c2ba0b..5614bb6e 100644 --- a/stream_str.go +++ b/stream_str.go @@ -315,7 +315,7 @@ func (stream *Stream) WriteString(s string) { i := 0 for ; i < valLen; i++ { c := s[i] - if c > 31 && c != '"' && c != '\\' { + if c < utf8.RuneSelf && safeSet[c] { stream.buf = append(stream.buf, c) } else { break From ca479af2c0fbcbc5b0f143c78a1ad1b3b381930e Mon Sep 17 00:00:00 2001 From: Kz Ho Date: Mon, 13 Mar 2023 17:55:52 +0800 Subject: [PATCH 2/2] Keep writeStringSlowPath & writeStringSlowPathWithHTMLEscaped func the same --- stream_str.go | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/stream_str.go b/stream_str.go index 5614bb6e..c065fe3a 100644 --- a/stream_str.go +++ b/stream_str.go @@ -362,8 +362,34 @@ func writeStringSlowPath(stream *Stream, i int, s string, valLen int) { start = i continue } - i++ - continue + c, size := utf8.DecodeRuneInString(s[i:]) + if c == utf8.RuneError && size == 1 { + if start < i { + stream.WriteRaw(s[start:i]) + } + stream.WriteRaw(`\ufffd`) + i++ + start = i + continue + } + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + if c == '\u2028' || c == '\u2029' { + if start < i { + stream.WriteRaw(s[start:i]) + } + stream.WriteRaw(`\u202`) + stream.writeByte(hex[c&0xF]) + i += size + start = i + continue + } + i += size } if start < len(s) { stream.WriteRaw(s[start:])