// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package json import ( "bytes" "fmt" "html/template" "net/http" "github.com/gin-gonic/gin/internal/json" "github.com/gin-gonic/gin/render/common" ) func init() { common.List["JSON"] = NewJSON common.List["IndentedJSON"] = NewIndentedJSON common.List["SecureJSON"] = NewSecureJSON common.List["JsonpJSON"] = NewJsonpJSON common.List["AsciiJSON"] = NewAsciiJSON } //NewJSON build a new JSON render func NewJSON(obj interface{}, _ map[string]string) common.Render { return JSON{Data: obj} } //NewIndentedJSON build a new IndentedJSON render func NewIndentedJSON(obj interface{}, _ map[string]string) common.Render { return IndentedJSON{Data: obj} } //NewSecureJSON build a new SecureJSON render func NewSecureJSON(obj interface{}, opts map[string]string) common.Render { return SecureJSON{Prefix: opts["Prefix"], Data: obj} } //NewJsonpJSON build a new JsonpJSON render func NewJsonpJSON(obj interface{}, opts map[string]string) common.Render { return JsonpJSON{Callback: opts["Callback"], Data: obj} } //NewAsciiJSON build a new AsciiJSON render func NewAsciiJSON(obj interface{}, _ map[string]string) common.Render { return AsciiJSON{Data: obj} } // JSON contains the given interface object. type JSON struct { Data interface{} } // IndentedJSON contains the given interface object. type IndentedJSON struct { Data interface{} } // SecureJSON contains the given interface object and its prefix. type SecureJSON struct { Prefix string Data interface{} } // JsonpJSON contains the given interface object its callback. type JsonpJSON struct { Callback string Data interface{} } // AsciiJSON contains the given interface object. type AsciiJSON struct { Data interface{} } // SecureJSONPrefix is a string which represents SecureJSON prefix. type SecureJSONPrefix string var jsonContentType = []string{"application/json; charset=utf-8"} var jsonpContentType = []string{"application/javascript; charset=utf-8"} var jsonAsciiContentType = []string{"application/json"} // Render (JSON) writes data with custom ContentType. func (r JSON) Render(w http.ResponseWriter) (err error) { if err = WriteJSON(w, r.Data); err != nil { panic(err) } return } // WriteContentType (JSON) writes JSON ContentType. func (r JSON) WriteContentType(w http.ResponseWriter) { common.WriteContentType(w, jsonContentType) } // WriteJSON marshals the given interface object and writes it with custom ContentType. func WriteJSON(w http.ResponseWriter, obj interface{}) error { common.WriteContentType(w, jsonContentType) jsonBytes, err := json.Marshal(obj) if err != nil { return err } _, err = w.Write(jsonBytes) return err } // Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType. func (r IndentedJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) jsonBytes, err := json.MarshalIndent(r.Data, "", " ") if err != nil { return err } _, err = w.Write(jsonBytes) return err } // WriteContentType (IndentedJSON) writes JSON ContentType. func (r IndentedJSON) WriteContentType(w http.ResponseWriter) { common.WriteContentType(w, jsonContentType) } // Render (SecureJSON) marshals the given interface object and writes it with custom ContentType. func (r SecureJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) jsonBytes, err := json.Marshal(r.Data) if err != nil { return err } // if the jsonBytes is array values if bytes.HasPrefix(jsonBytes, []byte("[")) && bytes.HasSuffix(jsonBytes, []byte("]")) { _, err = w.Write([]byte(r.Prefix)) if err != nil { return err } } _, err = w.Write(jsonBytes) return err } // WriteContentType (SecureJSON) writes JSON ContentType. func (r SecureJSON) WriteContentType(w http.ResponseWriter) { common.WriteContentType(w, jsonContentType) } // Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType. func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) ret, err := json.Marshal(r.Data) if err != nil { return err } if r.Callback == "" { _, err = w.Write(ret) return err } callback := template.JSEscapeString(r.Callback) _, err = w.Write([]byte(callback)) if err != nil { return err } _, err = w.Write([]byte("(")) if err != nil { return err } _, err = w.Write(ret) if err != nil { return err } _, err = w.Write([]byte(")")) if err != nil { return err } return nil } // WriteContentType (JsonpJSON) writes Javascript ContentType. func (r JsonpJSON) WriteContentType(w http.ResponseWriter) { common.WriteContentType(w, jsonpContentType) } // Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType. func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) ret, err := json.Marshal(r.Data) if err != nil { return err } var buffer bytes.Buffer for _, r := range string(ret) { cvt := string(r) if r >= 128 { cvt = fmt.Sprintf("\\u%04x", int64(r)) } buffer.WriteString(cvt) } _, err = w.Write(buffer.Bytes()) return err } // WriteContentType (AsciiJSON) writes JSON ContentType. func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { common.WriteContentType(w, jsonAsciiContentType) }