7 // htmlSafeSet holds the value true if the ASCII character with the given
8 // array position can be safely represented inside a JSON string, embedded
9 // inside of HTML <script> tags, without any additional escaping.
11 // All values are true except for the ASCII control characters (0-31), the
12 // double quote ("), the backslash character ("\"), HTML opening and closing
13 // tags ("<" and ">"), and the ampersand ("&").
14 var htmlSafeSet = [utf8.RuneSelf]bool{
113 // safeSet holds the value true if the ASCII character with the given array
114 // position can be represented inside a JSON string without any further
117 // All values are true except for the ASCII control characters (0-31), the
118 // double quote ("), and the backslash character ("\").
119 var safeSet = [utf8.RuneSelf]bool{
218 var hex = "0123456789abcdef"
220 // WriteStringWithHTMLEscaped write string to stream with html special characters escaped
221 func (stream *Stream) WriteStringWithHTMLEscaped(s string) {
223 stream.buf = append(stream.buf, '"')
224 // write string, the fast path, without utf8 and escape support
226 for ; i < valLen; i++ {
228 if c < utf8.RuneSelf && htmlSafeSet[c] {
229 stream.buf = append(stream.buf, c)
235 stream.buf = append(stream.buf, '"')
238 writeStringSlowPathWithHTMLEscaped(stream, i, s, valLen)
241 func writeStringSlowPathWithHTMLEscaped(stream *Stream, i int, s string, valLen int) {
243 // for the remaining parts, we process them char by char
245 if b := s[i]; b < utf8.RuneSelf {
251 stream.WriteRaw(s[start:i])
255 stream.writeTwoBytes('\\', b)
257 stream.writeTwoBytes('\\', 'n')
259 stream.writeTwoBytes('\\', 'r')
261 stream.writeTwoBytes('\\', 't')
263 // This encodes bytes < 0x20 except for \t, \n and \r.
264 // If escapeHTML is set, it also escapes <, >, and &
265 // because they can lead to security holes when
266 // user-controlled strings are rendered into JSON
267 // and served to some browsers.
268 stream.WriteRaw(`\u00`)
269 stream.writeTwoBytes(hex[b>>4], hex[b&0xF])
275 c, size := utf8.DecodeRuneInString(s[i:])
276 if c == utf8.RuneError && size == 1 {
278 stream.WriteRaw(s[start:i])
280 stream.WriteRaw(`\ufffd`)
285 // U+2028 is LINE SEPARATOR.
286 // U+2029 is PARAGRAPH SEPARATOR.
287 // They are both technically valid characters in JSON strings,
288 // but don't work in JSONP, which has to be evaluated as JavaScript,
289 // and can lead to security holes there. It is valid JSON to
290 // escape them, so we do so unconditionally.
291 // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
292 if c == '\u2028' || c == '\u2029' {
294 stream.WriteRaw(s[start:i])
296 stream.WriteRaw(`\u202`)
297 stream.writeByte(hex[c&0xF])
305 stream.WriteRaw(s[start:])
307 stream.writeByte('"')
310 // WriteString write string to stream without html escape
311 func (stream *Stream) WriteString(s string) {
313 stream.buf = append(stream.buf, '"')
314 // write string, the fast path, without utf8 and escape support
316 for ; i < valLen; i++ {
318 if c > 31 && c != '"' && c != '\\' {
319 stream.buf = append(stream.buf, c)
325 stream.buf = append(stream.buf, '"')
328 writeStringSlowPath(stream, i, s, valLen)
331 func writeStringSlowPath(stream *Stream, i int, s string, valLen int) {
333 // for the remaining parts, we process them char by char
335 if b := s[i]; b < utf8.RuneSelf {
341 stream.WriteRaw(s[start:i])
345 stream.writeTwoBytes('\\', b)
347 stream.writeTwoBytes('\\', 'n')
349 stream.writeTwoBytes('\\', 'r')
351 stream.writeTwoBytes('\\', 't')
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])
369 stream.WriteRaw(s[start:])
371 stream.writeByte('"')