diff --git a/README.md b/README.md
index ae183f92c8..053750bb5b 100644
--- a/README.md
+++ b/README.md
@@ -991,6 +991,34 @@ func main() {
}
```
+#### PureJSON
+
+Normally, JSON replaces special HTML characters with their unicode entities, e.g. `<` becomes `\u003c`. If you want to encode such characters literally, you can use PureJSON instead.
+This feature is unavailable in Go 1.6 and lower.
+
+```go
+func main() {
+ r := gin.Default()
+
+ // Serves unicode entities
+ r.GET("/json", func(c *gin.Context) {
+ c.JSON(200, gin.H{
+ "html": "Hello, world!",
+ })
+ })
+
+ // Serves literal characters
+ r.GET("/purejson", func(c *gin.Context) {
+ c.PureJSON(200, gin.H{
+ "html": "Hello, world!",
+ })
+ })
+
+ // listen and serve on 0.0.0.0:8080
+ r.Run(":8080)
+}
+```
+
### Serving static files
```go
diff --git a/context_17.go b/context_17.go
new file mode 100644
index 0000000000..8e9f75ad7b
--- /dev/null
+++ b/context_17.go
@@ -0,0 +1,17 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package gin
+
+import (
+ "github.com/gin-gonic/gin/render"
+)
+
+// PureJSON serializes the given struct as JSON into the response body.
+// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
+func (c *Context) PureJSON(code int, obj interface{}) {
+ c.Render(code, render.PureJSON{Data: obj})
+}
diff --git a/context_17_test.go b/context_17_test.go
new file mode 100644
index 0000000000..d2251904f2
--- /dev/null
+++ b/context_17_test.go
@@ -0,0 +1,27 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package gin
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+// Tests that the response is serialized as JSON
+// and Content-Type is set to application/json
+// and special HTML characters are preserved
+func TestContextRenderPureJSON(t *testing.T) {
+ w := httptest.NewRecorder()
+ c, _ := CreateTestContext(w)
+ c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": ""})
+ assert.Equal(t, http.StatusCreated, w.Code)
+ assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String())
+ assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type"))
+}
diff --git a/context_test.go b/context_test.go
index 675c2a4911..782f7bed59 100644
--- a/context_test.go
+++ b/context_test.go
@@ -619,14 +619,15 @@ func TestContextRenderPanicIfErr(t *testing.T) {
// Tests that the response is serialized as JSON
// and Content-Type is set to application/json
+// and special HTML characters are escaped
func TestContextRenderJSON(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
- c.JSON(http.StatusCreated, H{"foo": "bar"})
+ c.JSON(http.StatusCreated, H{"foo": "bar", "html": ""})
assert.Equal(t, http.StatusCreated, w.Code)
- assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
+ assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type"))
}
diff --git a/json/json.go b/json/json.go
index aa76aa3098..4f643c5617 100644
--- a/json/json.go
+++ b/json/json.go
@@ -12,4 +12,5 @@ var (
Marshal = json.Marshal
MarshalIndent = json.MarshalIndent
NewDecoder = json.NewDecoder
+ NewEncoder = json.NewEncoder
)
diff --git a/render/json_17.go b/render/json_17.go
new file mode 100644
index 0000000000..df0dc1458f
--- /dev/null
+++ b/render/json_17.go
@@ -0,0 +1,28 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package render
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin/json"
+)
+
+type PureJSON struct {
+ Data interface{}
+}
+
+func (r PureJSON) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+ encoder := json.NewEncoder(w)
+ encoder.SetEscapeHTML(false)
+ return encoder.Encode(r.Data)
+}
+
+func (r PureJSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonContentType)
+}
diff --git a/render/render_17_test.go b/render/render_17_test.go
new file mode 100644
index 0000000000..68330090f6
--- /dev/null
+++ b/render/render_17_test.go
@@ -0,0 +1,26 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package render
+
+import (
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRenderPureJSON(t *testing.T) {
+ w := httptest.NewRecorder()
+ data := map[string]interface{}{
+ "foo": "bar",
+ "html": "",
+ }
+ err := (PureJSON{data}).Render(w)
+ assert.NoError(t, err)
+ assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String())
+ assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
+}
diff --git a/render/render_test.go b/render/render_test.go
index cd20d01d37..fe9228e985 100644
--- a/render/render_test.go
+++ b/render/render_test.go
@@ -52,7 +52,8 @@ func TestRenderMsgPack(t *testing.T) {
func TestRenderJSON(t *testing.T) {
w := httptest.NewRecorder()
data := map[string]interface{}{
- "foo": "bar",
+ "foo": "bar",
+ "html": "",
}
(JSON{data}).WriteContentType(w)
@@ -61,7 +62,7 @@ func TestRenderJSON(t *testing.T) {
err := (JSON{data}).Render(w)
assert.NoError(t, err)
- assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
+ assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
}