Selaa lähdekoodia

codec: json: support HTMLCharsAsIs for encoding <>& as is (not as \uXXX sequence)

Currently, we always escape the html special characters like < > and &,
to prevent security holes when served from some browsers.

Unfortunately, there are times when we do not want this:
- put this string in a URI
- string should be easy to browse and read

Since we already defaulted to escaping them, we now add an option
to explicitly NOT escape them.

Fixes #189
Ugorji Nwoke 8 vuotta sitten
vanhempi
commit
c88ee250d0
4 muutettua tiedostoa jossa 22 lisäystä ja 5 poistoa
  1. 3 1
      codec/codec_test.go
  2. 2 0
      codec/helper_test.go
  3. 16 3
      codec/json.go
  4. 1 1
      codec/test.py

+ 3 - 1
codec/codec_test.go

@@ -107,6 +107,7 @@ func testInitFlags() {
 	flag.IntVar(&testMaxInitLen, "tx", 0, "Max Init Len")
 	flag.BoolVar(&testUseMust, "tm", true, "Use Must(En|De)code")
 	flag.BoolVar(&testCheckCircRef, "tl", false, "Use Check Circular Ref")
+	flag.BoolVar(&testJsonHTMLCharsAsIs, "tas", false, "Set JSON HTMLCharsAsIs")
 }
 
 func testByteBuf(in []byte) *bytes.Buffer {
@@ -357,6 +358,7 @@ func testInit() {
 	}
 
 	testJsonH.Indent = int8(testJsonIndent)
+	testJsonH.HTMLCharsAsIs = testJsonHTMLCharsAsIs
 	testMsgpackH.RawToString = true
 
 	// testMsgpackH.AddExt(byteSliceTyp, 0, testMsgpackH.BinaryEncodeExt, testMsgpackH.BinaryDecodeExt)
@@ -391,7 +393,7 @@ func testInit() {
 		true,
 		"null",
 		nil,
-		"someday",
+		"some&day>some<day",
 		timeToCompare1,
 		"",
 		timeToCompare2,

+ 2 - 0
codec/helper_test.go

@@ -91,6 +91,8 @@ var (
 	testCheckCircRef   bool
 	testJsonIndent     int
 	testMaxInitLen     int
+
+	testJsonHTMLCharsAsIs bool
 )
 
 func init() {

+ 16 - 3
codec/json.go

@@ -310,6 +310,8 @@ func (e *jsonEncDriver) quoteStr(s string) {
 	w.writen1('"')
 	start := 0
 	for i := 0; i < len(s); {
+		// encode all bytes < 0x20 (except \r, \n).
+		// also encode < > & to prevent security holes when served to some browsers.
 		if b := s[i]; b < utf8.RuneSelf {
 			if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
 				i++
@@ -331,9 +333,14 @@ func (e *jsonEncDriver) quoteStr(s string) {
 				w.writen2('\\', 'f')
 			case '\t':
 				w.writen2('\\', 't')
+			case '<', '>', '&':
+				if e.h.HTMLCharsAsIs {
+					w.writen1(b)
+				} else {
+					w.writestr(`\u00`)
+					w.writen2(hex[b>>4], hex[b&0xF])
+				}
 			default:
-				// encode all bytes < 0x20 (except \r, \n).
-				// also encode < > & to prevent security holes when served to some browsers.
 				w.writestr(`\u00`)
 				w.writen2(hex[b>>4], hex[b&0xF])
 			}
@@ -352,7 +359,7 @@ func (e *jsonEncDriver) quoteStr(s string) {
 			continue
 		}
 		// U+2028 is LINE SEPARATOR. U+2029 is PARAGRAPH SEPARATOR.
-		// Both technically valid JSON, but bomb on JSONP, so fix here.
+		// Both technically valid JSON, but bomb on JSONP, so fix here unconditionally.
 		if c == '\u2028' || c == '\u2029' {
 			if start < i {
 				w.writestr(s[start:i])
@@ -1173,6 +1180,12 @@ type JsonHandle struct {
 	//             containing the exact integer representation as a decimal.
 	//   - else    encode all integers as a json number (default)
 	IntegerAsString uint8
+
+	// HTMLCharsAsIs controls how to encode some special characters to html: < > &
+	//
+	// By default, we encode them as \uXXX
+	// to prevent security holes when served from some browsers.
+	HTMLCharsAsIs bool
 }
 
 func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {

+ 1 - 1
codec/test.py

@@ -34,7 +34,7 @@ def get_test_data_list():
          True,
          u"null",
          None,
-         u"someday",
+         u"some&day>some<day",
          1328176922000002000,
          u"",
          -2206187877999998000,