From ca479af2c0fbcbc5b0f143c78a1ad1b3b381930e Mon Sep 17 00:00:00 2001 From: Kz Ho Date: Mon, 13 Mar 2023 17:55:52 +0800 Subject: [PATCH] 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:])