1package render 2 3import ( 4 "bytes" 5 "encoding/json" 6 "encoding/xml" 7 "html/template" 8 "io" 9 "net/http" 10) 11 12// Engine is the generic interface for all responses. 13type Engine interface { 14 Render(io.Writer, interface{}) error 15} 16 17// Head defines the basic ContentType and Status fields. 18type Head struct { 19 ContentType string 20 Status int 21} 22 23// Data built-in renderer. 24type Data struct { 25 Head 26} 27 28// HTML built-in renderer. 29type HTML struct { 30 Head 31 Name string 32 Templates *template.Template 33} 34 35// JSON built-in renderer. 36type JSON struct { 37 Head 38 Indent bool 39 UnEscapeHTML bool 40 Prefix []byte 41 StreamingJSON bool 42} 43 44// JSONP built-in renderer. 45type JSONP struct { 46 Head 47 Indent bool 48 Callback string 49} 50 51// Text built-in renderer. 52type Text struct { 53 Head 54} 55 56// XML built-in renderer. 57type XML struct { 58 Head 59 Indent bool 60 Prefix []byte 61} 62 63// Write outputs the header content. 64func (h Head) Write(w http.ResponseWriter) { 65 w.Header().Set(ContentType, h.ContentType) 66 w.WriteHeader(h.Status) 67} 68 69// Render a data response. 70func (d Data) Render(w io.Writer, v interface{}) error { 71 if hw, ok := w.(http.ResponseWriter); ok { 72 c := hw.Header().Get(ContentType) 73 if c != "" { 74 d.Head.ContentType = c 75 } 76 d.Head.Write(hw) 77 } 78 79 w.Write(v.([]byte)) 80 return nil 81} 82 83// Render a HTML response. 84func (h HTML) Render(w io.Writer, binding interface{}) error { 85 // Retrieve a buffer from the pool to write to. 86 out := bufPool.Get() 87 err := h.Templates.ExecuteTemplate(out, h.Name, binding) 88 if err != nil { 89 return err 90 } 91 92 if hw, ok := w.(http.ResponseWriter); ok { 93 h.Head.Write(hw) 94 } 95 out.WriteTo(w) 96 97 // Return the buffer to the pool. 98 bufPool.Put(out) 99 return nil 100} 101 102// Render a JSON response. 103func (j JSON) Render(w io.Writer, v interface{}) error { 104 if j.StreamingJSON { 105 return j.renderStreamingJSON(w, v) 106 } 107 108 var result []byte 109 var err error 110 111 if j.Indent { 112 result, err = json.MarshalIndent(v, "", " ") 113 result = append(result, '\n') 114 } else { 115 result, err = json.Marshal(v) 116 } 117 if err != nil { 118 return err 119 } 120 121 // Unescape HTML if needed. 122 if j.UnEscapeHTML { 123 result = bytes.Replace(result, []byte("\\u003c"), []byte("<"), -1) 124 result = bytes.Replace(result, []byte("\\u003e"), []byte(">"), -1) 125 result = bytes.Replace(result, []byte("\\u0026"), []byte("&"), -1) 126 } 127 128 // JSON marshaled fine, write out the result. 129 if hw, ok := w.(http.ResponseWriter); ok { 130 j.Head.Write(hw) 131 } 132 if len(j.Prefix) > 0 { 133 w.Write(j.Prefix) 134 } 135 w.Write(result) 136 return nil 137} 138 139func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error { 140 if hw, ok := w.(http.ResponseWriter); ok { 141 j.Head.Write(hw) 142 } 143 if len(j.Prefix) > 0 { 144 w.Write(j.Prefix) 145 } 146 147 return json.NewEncoder(w).Encode(v) 148} 149 150// Render a JSONP response. 151func (j JSONP) Render(w io.Writer, v interface{}) error { 152 var result []byte 153 var err error 154 155 if j.Indent { 156 result, err = json.MarshalIndent(v, "", " ") 157 } else { 158 result, err = json.Marshal(v) 159 } 160 if err != nil { 161 return err 162 } 163 164 // JSON marshaled fine, write out the result. 165 if hw, ok := w.(http.ResponseWriter); ok { 166 j.Head.Write(hw) 167 } 168 w.Write([]byte(j.Callback + "(")) 169 w.Write(result) 170 w.Write([]byte(");")) 171 172 // If indenting, append a new line. 173 if j.Indent { 174 w.Write([]byte("\n")) 175 } 176 return nil 177} 178 179// Render a text response. 180func (t Text) Render(w io.Writer, v interface{}) error { 181 if hw, ok := w.(http.ResponseWriter); ok { 182 c := hw.Header().Get(ContentType) 183 if c != "" { 184 t.Head.ContentType = c 185 } 186 t.Head.Write(hw) 187 } 188 189 w.Write([]byte(v.(string))) 190 return nil 191} 192 193// Render an XML response. 194func (x XML) Render(w io.Writer, v interface{}) error { 195 var result []byte 196 var err error 197 198 if x.Indent { 199 result, err = xml.MarshalIndent(v, "", " ") 200 result = append(result, '\n') 201 } else { 202 result, err = xml.Marshal(v) 203 } 204 if err != nil { 205 return err 206 } 207 208 // XML marshaled fine, write out the result. 209 if hw, ok := w.(http.ResponseWriter); ok { 210 x.Head.Write(hw) 211 } 212 if len(x.Prefix) > 0 { 213 w.Write(x.Prefix) 214 } 215 w.Write(result) 216 return nil 217} 218