mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
318 lines
6.8 KiB
Go
318 lines
6.8 KiB
Go
package rest
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
|
|
"github.com/klauspost/compress/gzip"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
// Engine is the generic interface for all responses.
|
|
type Engine interface {
|
|
Render(*fasthttp.RequestCtx, interface{}) error
|
|
//used only if config gzip is enabled
|
|
RenderGzip(*fasthttp.RequestCtx, 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
|
|
}
|
|
|
|
// 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(ctx *fasthttp.RequestCtx) {
|
|
ctx.Response.Header.Set(ContentType, h.ContentType)
|
|
ctx.SetStatusCode(h.Status)
|
|
}
|
|
|
|
// Render a data response.
|
|
func (d Data) Render(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
c := string(ctx.Request.Header.Peek(ContentType))
|
|
w := ctx.Response.BodyWriter()
|
|
if c != "" {
|
|
d.Head.ContentType = c
|
|
}
|
|
|
|
d.Head.Write(ctx)
|
|
w.Write(v.([]byte))
|
|
return nil
|
|
|
|
}
|
|
|
|
// RenderGzip a data response using gzip compression.
|
|
func (d Data) RenderGzip(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
c := string(ctx.Request.Header.Peek(ContentType))
|
|
if c != "" {
|
|
d.Head.ContentType = c
|
|
}
|
|
|
|
d.Head.Write(ctx)
|
|
_, err := fasthttp.WriteGzip(ctx.Response.BodyWriter(), v.([]byte))
|
|
if err == nil {
|
|
ctx.Response.Header.Add("Content-Encoding", "gzip")
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Render a JSON response.
|
|
func (j JSON) Render(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
if j.StreamingJSON {
|
|
return j.renderStreamingJSON(ctx, 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)
|
|
}
|
|
w := ctx.Response.BodyWriter()
|
|
// JSON marshaled fine, write out the result.
|
|
j.Head.Write(ctx)
|
|
if len(j.Prefix) > 0 {
|
|
w.Write(j.Prefix)
|
|
}
|
|
w.Write(result)
|
|
return nil
|
|
}
|
|
|
|
// RenderGzip a JSON response using gzip compression.
|
|
func (j JSON) RenderGzip(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
if j.StreamingJSON {
|
|
return j.renderStreamingJSONGzip(ctx, 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
|
|
}
|
|
ctx.Response.Header.Add("Content-Encoding", "gzip")
|
|
|
|
// 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)
|
|
}
|
|
w := gzip.NewWriter(ctx.Response.BodyWriter())
|
|
// JSON marshaled fine, write out the result.
|
|
j.Head.Write(ctx)
|
|
if len(j.Prefix) > 0 {
|
|
w.Write(j.Prefix)
|
|
}
|
|
w.Write(result)
|
|
w.Close()
|
|
return nil
|
|
}
|
|
|
|
func (j JSON) renderStreamingJSON(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
j.Head.Write(ctx)
|
|
w := ctx.Response.BodyWriter()
|
|
if len(j.Prefix) > 0 {
|
|
w.Write(j.Prefix)
|
|
}
|
|
return json.NewEncoder(w).Encode(v)
|
|
}
|
|
|
|
func (j JSON) renderStreamingJSONGzip(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
ctx.Response.Header.Add("Content-Encoding", "gzip")
|
|
j.Head.Write(ctx)
|
|
w := gzip.NewWriter(ctx.Response.BodyWriter())
|
|
if len(j.Prefix) > 0 {
|
|
w.Write(j.Prefix)
|
|
}
|
|
w.Close()
|
|
return json.NewEncoder(w).Encode(v)
|
|
}
|
|
|
|
// Render a JSONP response.
|
|
func (j JSONP) Render(ctx *fasthttp.RequestCtx, 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
|
|
}
|
|
w := ctx.Response.BodyWriter()
|
|
|
|
// JSON marshaled fine, write out the result.
|
|
j.Head.Write(ctx)
|
|
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
|
|
}
|
|
|
|
// RenderGzip a JSONP response using gzip compression.
|
|
func (j JSONP) RenderGzip(ctx *fasthttp.RequestCtx, 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
|
|
}
|
|
w := gzip.NewWriter(ctx.Response.BodyWriter())
|
|
|
|
ctx.Response.Header.Add("Content-Encoding", "gzip")
|
|
// JSON marshaled fine, write out the result.
|
|
j.Head.Write(ctx)
|
|
w.Write([]byte(j.Callback + "("))
|
|
w.Write(result)
|
|
w.Write([]byte(");"))
|
|
|
|
// If indenting, append a new line.
|
|
if j.Indent {
|
|
w.Write([]byte("\n"))
|
|
}
|
|
w.Close()
|
|
return nil
|
|
}
|
|
|
|
// Render a text response.
|
|
func (t Text) Render(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
c := string(ctx.Request.Header.Peek(ContentType))
|
|
if c != "" {
|
|
t.Head.ContentType = c
|
|
}
|
|
w := ctx.Response.BodyWriter()
|
|
t.Head.Write(ctx)
|
|
w.Write([]byte(v.(string)))
|
|
return nil
|
|
}
|
|
|
|
// RenderGzip a Text response using gzip compression.
|
|
func (t Text) RenderGzip(ctx *fasthttp.RequestCtx, v interface{}) error {
|
|
c := string(ctx.Request.Header.Peek(ContentType))
|
|
if c != "" {
|
|
t.Head.ContentType = c
|
|
}
|
|
ctx.Response.Header.Add("Content-Encoding", "gzip")
|
|
t.Head.Write(ctx)
|
|
fasthttp.WriteGzip(ctx.Response.BodyWriter(), []byte(v.(string)))
|
|
|
|
return nil
|
|
}
|
|
|
|
// Render an XML response.
|
|
func (x XML) Render(ctx *fasthttp.RequestCtx, 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.
|
|
x.Head.Write(ctx)
|
|
w := ctx.Response.BodyWriter()
|
|
if len(x.Prefix) > 0 {
|
|
w.Write(x.Prefix)
|
|
}
|
|
w.Write(result)
|
|
return nil
|
|
}
|
|
|
|
// RenderGzip an XML response using gzip compression.
|
|
func (x XML) RenderGzip(ctx *fasthttp.RequestCtx, 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
|
|
}
|
|
ctx.Response.Header.Add("Content-Encoding", "gzip")
|
|
// XML marshaled fine, write out the result.
|
|
x.Head.Write(ctx)
|
|
w := gzip.NewWriter(ctx.Response.BodyWriter())
|
|
if len(x.Prefix) > 0 {
|
|
w.Write(x.Prefix)
|
|
}
|
|
w.Write(result)
|
|
w.Close()
|
|
return nil
|
|
}
|