diff --git a/_examples/response-writer/write-rest/main.go b/_examples/response-writer/write-rest/main.go index 5e757827..84d3332a 100644 --- a/_examples/response-writer/write-rest/main.go +++ b/_examples/response-writer/write-rest/main.go @@ -4,7 +4,6 @@ import ( "encoding/xml" "github.com/kataras/iris/v12" - "github.com/kataras/iris/v12/context" ) // User example struct for json and msgpack. @@ -53,6 +52,42 @@ func main() { ctx.JSON(u) }) + // Use Secure field to prevent json hijacking. + // It prepends `"while(1),"` to the body when the data is array. + app.Get("/json_secure", func(ctx iris.Context) { + response := []string{"val1", "val2", "val3"} + options := iris.JSON{Indent: "", Secure: true} + ctx.JSON(response, options) + + // Will output: while(1);["val1","val2","val3"] + }) + + // Use ASCII field to generate ASCII-only JSON + // with escaped non-ASCII characters. + app.Get("/json_ascii", func(ctx iris.Context) { + response := iris.Map{"lang": "GO-虹膜", "tag": "
"} + options := iris.JSON{Indent: " ", ASCII: true} + ctx.JSON(response, options) + + /* Will output: + { + "lang": "GO-\u8679\u819c", + "tag": "\u003cbr\u003e" + } + */ + }) + + // Do not replace special HTML characters with their unicode entities + // using the UnescapeHTML field. + app.Get("/json_raw", func(ctx iris.Context) { + options := iris.JSON{UnescapeHTML: true} + ctx.JSON(iris.Map{ + "html": "Hello, world!", + }, options) + + // Will output: {"html":"Hello, world!"} + }) + // Other content types, app.Get("/binary", func(ctx iris.Context) { @@ -69,7 +104,7 @@ func main() { }) app.Get("/jsonp", func(ctx iris.Context) { - ctx.JSONP(map[string]string{"hello": "jsonp"}, context.JSONP{Callback: "callbackName"}) + ctx.JSONP(map[string]string{"hello": "jsonp"}, iris.JSONP{Callback: "callbackName"}) }) app.Get("/xml", func(ctx iris.Context) { @@ -105,6 +140,8 @@ func main() { // http://localhost:8080/decode // http://localhost:8080/encode + // http://localhost:8080/json_secure + // http://localhost:8080/json_ascii // // http://localhost:8080/binary // http://localhost:8080/text diff --git a/aliases.go b/aliases.go index 3be42fd9..26014666 100644 --- a/aliases.go +++ b/aliases.go @@ -76,6 +76,10 @@ type ( // // It is an alias of the `context#JSON` type. JSON = context.JSON + // JSONP the optional settings for JSONP renderer. + // + // It is an alias of the `context#JSONP` type. + JSONP = context.JSONP // ProtoMarshalOptions is a type alias for protojson.MarshalOptions. ProtoMarshalOptions = context.ProtoMarshalOptions // ProtoUnmarshalOptions is a type alias for protojson.UnmarshalOptions. diff --git a/context/context.go b/context/context.go index a70907d6..3094b94e 100644 --- a/context/context.go +++ b/context/context.go @@ -3097,16 +3097,27 @@ func WriteJSON(writer io.Writer, v interface{}, options JSON, optimize bool) (in return 0, err } + prependSecure := false + if options.Secure { + if bytes.HasPrefix(result, jsonArrayPrefix) { + if options.Indent == "" { + prependSecure = bytes.HasSuffix(result, jsonArraySuffix) + } else { + prependSecure = bytes.HasSuffix(bytes.TrimRightFunc(result, func(r rune) bool { + return r == '\n' || r == '\r' + }), jsonArraySuffix) + } + } + } + if options.UnescapeHTML { result = bytes.Replace(result, ltHex, lt, -1) result = bytes.Replace(result, gtHex, gt, -1) result = bytes.Replace(result, andHex, and, -1) } - if options.Secure { - if bytes.HasPrefix(result, jsonArrayPrefix) && bytes.HasSuffix(result, jsonArraySuffix) { - result = append(secureJSONPrefix, result...) - } + if prependSecure { + result = append(secureJSONPrefix, result...) } if options.ASCII {