1// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
2// Use of this source code is governed by a MIT style
3// license that can be found in the LICENSE file.
4
5package render
6
7import (
8	"bytes"
9	"fmt"
10	"html/template"
11	"net/http"
12
13	"github.com/gin-gonic/gin/json"
14)
15
16type JSON struct {
17	Data interface{}
18}
19
20type IndentedJSON struct {
21	Data interface{}
22}
23
24type SecureJSON struct {
25	Prefix string
26	Data   interface{}
27}
28
29type JsonpJSON struct {
30	Callback string
31	Data     interface{}
32}
33
34type AsciiJSON struct {
35	Data interface{}
36}
37
38type SecureJSONPrefix string
39
40var jsonContentType = []string{"application/json; charset=utf-8"}
41var jsonpContentType = []string{"application/javascript; charset=utf-8"}
42var jsonAsciiContentType = []string{"application/json"}
43
44func (r JSON) Render(w http.ResponseWriter) (err error) {
45	if err = WriteJSON(w, r.Data); err != nil {
46		panic(err)
47	}
48	return
49}
50
51func (r JSON) WriteContentType(w http.ResponseWriter) {
52	writeContentType(w, jsonContentType)
53}
54
55func WriteJSON(w http.ResponseWriter, obj interface{}) error {
56	writeContentType(w, jsonContentType)
57	jsonBytes, err := json.Marshal(obj)
58	if err != nil {
59		return err
60	}
61	w.Write(jsonBytes)
62	return nil
63}
64
65func (r IndentedJSON) Render(w http.ResponseWriter) error {
66	r.WriteContentType(w)
67	jsonBytes, err := json.MarshalIndent(r.Data, "", "    ")
68	if err != nil {
69		return err
70	}
71	w.Write(jsonBytes)
72	return nil
73}
74
75func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
76	writeContentType(w, jsonContentType)
77}
78
79func (r SecureJSON) Render(w http.ResponseWriter) error {
80	r.WriteContentType(w)
81	jsonBytes, err := json.Marshal(r.Data)
82	if err != nil {
83		return err
84	}
85	// if the jsonBytes is array values
86	if bytes.HasPrefix(jsonBytes, []byte("[")) && bytes.HasSuffix(jsonBytes, []byte("]")) {
87		w.Write([]byte(r.Prefix))
88	}
89	w.Write(jsonBytes)
90	return nil
91}
92
93func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
94	writeContentType(w, jsonContentType)
95}
96
97func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
98	r.WriteContentType(w)
99	ret, err := json.Marshal(r.Data)
100	if err != nil {
101		return err
102	}
103
104	if r.Callback == "" {
105		w.Write(ret)
106		return nil
107	}
108
109	callback := template.JSEscapeString(r.Callback)
110	w.Write([]byte(callback))
111	w.Write([]byte("("))
112	w.Write(ret)
113	w.Write([]byte(")"))
114
115	return nil
116}
117
118func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
119	writeContentType(w, jsonpContentType)
120}
121
122func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
123	r.WriteContentType(w)
124	ret, err := json.Marshal(r.Data)
125	if err != nil {
126		return err
127	}
128
129	var buffer bytes.Buffer
130	for _, r := range string(ret) {
131		cvt := ""
132		if r < 128 {
133			cvt = string(r)
134		} else {
135			cvt = fmt.Sprintf("\\u%04x", int64(r))
136		}
137		buffer.WriteString(cvt)
138	}
139
140	w.Write(buffer.Bytes())
141	return nil
142}
143
144func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
145	writeContentType(w, jsonAsciiContentType)
146}
147