218 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
| package render
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"encoding/xml"
 | |
| 	"html/template"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| )
 | |
| 
 | |
| // Engine is the generic interface for all responses.
 | |
| type Engine interface {
 | |
| 	Render(io.Writer, interface{}) error
 | |
| }
 | |
| 
 | |
| // Head defines the basic ContentType and Status fields.
 | |
| type Head struct {
 | |
| 	ContentType string
 | |
| 	Status      int
 | |
| }
 | |
| 
 | |
| // Data built-in renderer.
 | |
| type Data struct {
 | |
| 	Head
 | |
| }
 | |
| 
 | |
| // HTML built-in renderer.
 | |
| type HTML struct {
 | |
| 	Head
 | |
| 	Name      string
 | |
| 	Templates *template.Template
 | |
| }
 | |
| 
 | |
| // JSON built-in renderer.
 | |
| type JSON struct {
 | |
| 	Head
 | |
| 	Indent        bool
 | |
| 	UnEscapeHTML  bool
 | |
| 	Prefix        []byte
 | |
| 	StreamingJSON bool
 | |
| }
 | |
| 
 | |
| // JSONP built-in renderer.
 | |
| type JSONP struct {
 | |
| 	Head
 | |
| 	Indent   bool
 | |
| 	Callback string
 | |
| }
 | |
| 
 | |
| // Text built-in renderer.
 | |
| type Text struct {
 | |
| 	Head
 | |
| }
 | |
| 
 | |
| // XML built-in renderer.
 | |
| type XML struct {
 | |
| 	Head
 | |
| 	Indent bool
 | |
| 	Prefix []byte
 | |
| }
 | |
| 
 | |
| // Write outputs the header content.
 | |
| func (h Head) Write(w http.ResponseWriter) {
 | |
| 	w.Header().Set(ContentType, h.ContentType)
 | |
| 	w.WriteHeader(h.Status)
 | |
| }
 | |
| 
 | |
| // Render a data response.
 | |
| func (d Data) Render(w io.Writer, v interface{}) error {
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		c := hw.Header().Get(ContentType)
 | |
| 		if c != "" {
 | |
| 			d.Head.ContentType = c
 | |
| 		}
 | |
| 		d.Head.Write(hw)
 | |
| 	}
 | |
| 
 | |
| 	w.Write(v.([]byte))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Render a HTML response.
 | |
| func (h HTML) Render(w io.Writer, binding interface{}) error {
 | |
| 	// Retrieve a buffer from the pool to write to.
 | |
| 	out := bufPool.Get()
 | |
| 	err := h.Templates.ExecuteTemplate(out, h.Name, binding)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		h.Head.Write(hw)
 | |
| 	}
 | |
| 	out.WriteTo(w)
 | |
| 
 | |
| 	// Return the buffer to the pool.
 | |
| 	bufPool.Put(out)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Render a JSON response.
 | |
| func (j JSON) Render(w io.Writer, v interface{}) error {
 | |
| 	if j.StreamingJSON {
 | |
| 		return j.renderStreamingJSON(w, v)
 | |
| 	}
 | |
| 
 | |
| 	var result []byte
 | |
| 	var err error
 | |
| 
 | |
| 	if j.Indent {
 | |
| 		result, err = json.MarshalIndent(v, "", "  ")
 | |
| 		result = append(result, '\n')
 | |
| 	} else {
 | |
| 		result, err = json.Marshal(v)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Unescape HTML if needed.
 | |
| 	if j.UnEscapeHTML {
 | |
| 		result = bytes.Replace(result, []byte("\\u003c"), []byte("<"), -1)
 | |
| 		result = bytes.Replace(result, []byte("\\u003e"), []byte(">"), -1)
 | |
| 		result = bytes.Replace(result, []byte("\\u0026"), []byte("&"), -1)
 | |
| 	}
 | |
| 
 | |
| 	// JSON marshaled fine, write out the result.
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		j.Head.Write(hw)
 | |
| 	}
 | |
| 	if len(j.Prefix) > 0 {
 | |
| 		w.Write(j.Prefix)
 | |
| 	}
 | |
| 	w.Write(result)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error {
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		j.Head.Write(hw)
 | |
| 	}
 | |
| 	if len(j.Prefix) > 0 {
 | |
| 		w.Write(j.Prefix)
 | |
| 	}
 | |
| 
 | |
| 	return json.NewEncoder(w).Encode(v)
 | |
| }
 | |
| 
 | |
| // Render a JSONP response.
 | |
| func (j JSONP) Render(w io.Writer, v interface{}) error {
 | |
| 	var result []byte
 | |
| 	var err error
 | |
| 
 | |
| 	if j.Indent {
 | |
| 		result, err = json.MarshalIndent(v, "", "  ")
 | |
| 	} else {
 | |
| 		result, err = json.Marshal(v)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// JSON marshaled fine, write out the result.
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		j.Head.Write(hw)
 | |
| 	}
 | |
| 	w.Write([]byte(j.Callback + "("))
 | |
| 	w.Write(result)
 | |
| 	w.Write([]byte(");"))
 | |
| 
 | |
| 	// If indenting, append a new line.
 | |
| 	if j.Indent {
 | |
| 		w.Write([]byte("\n"))
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Render a text response.
 | |
| func (t Text) Render(w io.Writer, v interface{}) error {
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		c := hw.Header().Get(ContentType)
 | |
| 		if c != "" {
 | |
| 			t.Head.ContentType = c
 | |
| 		}
 | |
| 		t.Head.Write(hw)
 | |
| 	}
 | |
| 
 | |
| 	w.Write([]byte(v.(string)))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Render an XML response.
 | |
| func (x XML) Render(w io.Writer, v interface{}) error {
 | |
| 	var result []byte
 | |
| 	var err error
 | |
| 
 | |
| 	if x.Indent {
 | |
| 		result, err = xml.MarshalIndent(v, "", "  ")
 | |
| 		result = append(result, '\n')
 | |
| 	} else {
 | |
| 		result, err = xml.Marshal(v)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// XML marshaled fine, write out the result.
 | |
| 	if hw, ok := w.(http.ResponseWriter); ok {
 | |
| 		x.Head.Write(hw)
 | |
| 	}
 | |
| 	if len(x.Prefix) > 0 {
 | |
| 		w.Write(x.Prefix)
 | |
| 	}
 | |
| 	w.Write(result)
 | |
| 	return nil
 | |
| }
 |