1
0
mirror of https://github.com/gofiber/fiber.git synced 2025-02-22 23:24:32 +00:00
fiber/response.go
2020-02-16 18:00:14 +01:00

484 lines
12 KiB
Go

// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖
// 📌 Please open an issue if you got suggestions or found a bug!
// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki
// 🦸 Not all heroes wear capes, thank you to some amazing people
// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr
package fiber
import (
"bytes"
"encoding/xml"
"fmt"
"html/template"
"io/ioutil"
"log"
"path/filepath"
"strings"
"time"
"github.com/CloudyKit/jet"
"github.com/aymerick/raymond"
"github.com/cbroglie/mustache"
"github.com/eknkc/amber"
jsoniter "github.com/json-iterator/go"
fasthttp "github.com/valyala/fasthttp"
"github.com/yosssi/ace"
)
// Cookie : struct
type Cookie struct {
Expire int // time.Unix(1578981376, 0)
MaxAge int
Domain string
Path string
HTTPOnly bool
Secure bool
SameSite string
}
// Append : https://fiber.wiki/context#append
func (ctx *Ctx) Append(field string, values ...string) {
if len(values) == 0 {
return
}
h := getString(ctx.Fasthttp.Response.Header.Peek(field))
for i := range values {
if h == "" {
h += values[i]
} else {
h += ", " + values[i]
}
}
ctx.Set(field, h)
}
// Attachment : https://fiber.wiki/context#attachment
func (ctx *Ctx) Attachment(name ...string) {
if len(name) > 0 {
filename := filepath.Base(name[0])
ctx.Type(filepath.Ext(filename))
ctx.Set(fasthttp.HeaderContentDisposition, `attachment; filename="`+filename+`"`)
return
}
ctx.Set(fasthttp.HeaderContentDisposition, "attachment")
}
// ClearCookie : https://fiber.wiki/context#clearcookie
func (ctx *Ctx) ClearCookie(name ...string) {
if len(name) > 0 {
for i := range name {
//ctx.Fasthttp.Request.Header.DelAllCookies()
ctx.Fasthttp.Response.Header.DelClientCookie(name[i])
}
return
}
//ctx.Fasthttp.Response.Header.DelAllCookies()
ctx.Fasthttp.Request.Header.VisitAllCookie(func(k, v []byte) {
ctx.Fasthttp.Response.Header.DelClientCookie(getString(k))
})
}
// Cookie : https://fiber.wiki/context#cookie
func (ctx *Ctx) Cookie(key, value string, options ...interface{}) {
cook := &fasthttp.Cookie{}
cook.SetKey(key)
cook.SetValue(value)
if len(options) > 0 {
switch opt := options[0].(type) {
case *Cookie:
if opt.Expire > 0 {
cook.SetExpire(time.Unix(int64(opt.Expire), 0))
}
if opt.MaxAge > 0 {
cook.SetMaxAge(opt.MaxAge)
}
if opt.Domain != "" {
cook.SetDomain(opt.Domain)
}
if opt.Path != "" {
cook.SetPath(opt.Path)
}
if opt.HTTPOnly {
cook.SetHTTPOnly(opt.HTTPOnly)
}
if opt.Secure {
cook.SetSecure(opt.Secure)
}
if opt.SameSite != "" {
sameSite := fasthttp.CookieSameSiteDefaultMode
if strings.EqualFold(opt.SameSite, "lax") {
sameSite = fasthttp.CookieSameSiteLaxMode
} else if strings.EqualFold(opt.SameSite, "strict") {
sameSite = fasthttp.CookieSameSiteStrictMode
} else if strings.EqualFold(opt.SameSite, "none") {
sameSite = fasthttp.CookieSameSiteNoneMode
}
// } else {
// sameSite = fasthttp.CookieSameSiteDisabled
// }
cook.SetSameSite(sameSite)
}
default:
log.Println("Cookie: Invalid &Cookie{} struct")
}
}
ctx.Fasthttp.Response.Header.SetCookie(cook)
}
// Download : https://fiber.wiki/context#download
func (ctx *Ctx) Download(file string, name ...string) {
filename := filepath.Base(file)
if len(name) > 0 {
filename = name[0]
}
ctx.Set(fasthttp.HeaderContentDisposition, "attachment; filename="+filename)
ctx.SendFile(file)
}
// End : https://fiber.wiki/context#end
func (ctx *Ctx) End() {
}
// Format : https://fiber.wiki/context#format
func (ctx *Ctx) Format(args ...interface{}) {
var body string
accept := ctx.Accepts("html", "json")
for i := range args {
switch arg := args[i].(type) {
case string:
body = arg
case []byte:
body = getString(arg)
default:
body = fmt.Sprintf("%v", arg)
}
switch accept {
case "html":
ctx.SendString("<p>" + body + "</p>")
case "json":
if err := ctx.JSON(body); err != nil {
log.Println("Format: error serializing json ", err)
}
default:
ctx.SendString(body)
}
}
}
// HeadersSent indicates if the app sent HTTP headers for the response.
// func (ctx *Ctx) HeadersSent() {}
// Json will be removed in v2
func (ctx *Ctx) Json(v interface{}) error {
fmt.Println("Fiber deprecated c.Json(), this will be removed in v2: Use c.JSON() instead")
return ctx.JSON(v)
}
// JSON : https://fiber.wiki/context#json
func (ctx *Ctx) JSON(v interface{}) error {
ctx.Fasthttp.Response.Header.SetContentType(mimeApplicationJSON)
raw, err := jsoniter.Marshal(&v)
if err != nil {
ctx.Fasthttp.Response.SetBodyString("")
return err
}
ctx.Fasthttp.Response.SetBodyString(getString(raw))
return nil
}
// JsonBytes ...
func (ctx *Ctx) JsonBytes(raw []byte) {
ctx.JSONBytes(raw)
}
// JSONBytes will be removed in v2
func (ctx *Ctx) JSONBytes(raw []byte) {
fmt.Println("Fiber deprecated c.JSONBytes(), this will function be removed in v2")
ctx.Fasthttp.Response.Header.SetContentType(mimeApplicationJSON)
ctx.Fasthttp.Response.SetBodyString(getString(raw))
}
// Jsonp will be removed in v2
func (ctx *Ctx) Jsonp(v interface{}, cb ...string) error {
fmt.Println("Fiber deprecated c.Jsonp(), this will be removed in v2: Use c.JSONP() instead")
return ctx.JSONP(v, cb...)
}
// JSONP : https://fiber.wiki/context#jsonp
func (ctx *Ctx) JSONP(v interface{}, cb ...string) error {
raw, err := jsoniter.Marshal(&v)
if err != nil {
return err
}
str := "callback("
if len(cb) > 0 {
str = cb[0] + "("
}
str += getString(raw) + ");"
ctx.Set(fasthttp.HeaderXContentTypeOptions, "nosniff")
ctx.Fasthttp.Response.Header.SetContentType(mimeApplicationJavascript)
ctx.Fasthttp.Response.SetBodyString(str)
return nil
}
// JsonString ...
func (ctx *Ctx) JsonString(raw string) {
ctx.JSONString(raw)
}
// JSONString will be removed in v2
func (ctx *Ctx) JSONString(raw string) {
fmt.Println("Fiber deprecated c.JSONString(), this function will be removed in v2")
ctx.Fasthttp.Response.Header.SetContentType(mimeApplicationJSON)
ctx.Fasthttp.Response.SetBodyString(raw)
}
// Links : https://fiber.wiki/context#links
func (ctx *Ctx) Links(link ...string) {
h := ""
for i, l := range link {
if i%2 == 0 {
h += "<" + l + ">"
} else {
h += `; rel="` + l + `",`
}
}
if len(link) > 0 {
h = strings.TrimSuffix(h, ",")
ctx.Set(fasthttp.HeaderLink, h)
}
}
// Location : https://fiber.wiki/context#location
func (ctx *Ctx) Location(path string) {
ctx.Set(fasthttp.HeaderLocation, path)
}
// Next : https://fiber.wiki/context#next
func (ctx *Ctx) Next(err ...error) {
ctx.route = nil
ctx.next = true
ctx.params = nil
ctx.values = nil
if len(err) > 0 {
ctx.error = err[0]
}
}
// Redirect : https://fiber.wiki/context#redirect
func (ctx *Ctx) Redirect(path string, status ...int) {
code := 302
if len(status) > 0 {
code = status[0]
}
ctx.Set(fasthttp.HeaderLocation, path)
ctx.Fasthttp.Response.SetStatusCode(code)
}
// Render : https://fiber.wiki/context#render
func (ctx *Ctx) Render(file string, v ...interface{}) error {
var err error
var raw []byte
var html string
var data interface{}
var tmpl *template.Template
if len(v) > 0 {
data = v[0]
}
if raw, err = ioutil.ReadFile(file); err != nil {
return err
}
engine := filepath.Ext(file)
switch engine {
case ".template": // https://golang.org/pkg/text/template/
if tmpl, err = template.New("test").Parse(getString(raw)); err != nil {
return err
}
var buf bytes.Buffer
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
case ".ace": // https://github.com/yosssi/ace
if tmpl, err = ace.Load(strings.TrimSuffix(file, filepath.Ext(file)), "", nil); err != nil {
return err
}
var buf bytes.Buffer
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
case ".amber": // https://github.com/eknkc/amber
if tmpl, err = amber.Compile(getString(raw), amber.DefaultOptions); err != nil {
return err
}
var buf bytes.Buffer
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
case ".jet": // https://github.com/CloudyKit/jet
d, f := filepath.Split(file)
var jetview = jet.NewHTMLSet(d)
var t *jet.Template
if t, err = jetview.GetTemplate(f); err != nil {
return err
}
var buf bytes.Buffer
if err = t.Execute(&buf, make(jet.VarMap), data); err != nil {
return err
}
html = buf.String()
case ".mustache": // https://github.com/hoisie/mustache
if html, err = mustache.Render(getString(raw), data); err != nil {
return err
}
case ".raymond": // https://github.com/aymerick/raymond
if html, err = raymond.Render(getString(raw), data); err != nil {
return err
}
default:
err = fmt.Errorf("render: does not support the %s extension", engine)
}
ctx.Set("Content-Type", "text/html")
ctx.SendString(html)
return err
}
// Send : https://fiber.wiki/context#send
func (ctx *Ctx) Send(args ...interface{}) {
if len(args) == 0 {
return
}
switch body := args[0].(type) {
case string:
ctx.Fasthttp.Response.SetBodyString(body)
case []byte:
ctx.Fasthttp.Response.SetBodyString(getString(body))
default:
ctx.Fasthttp.Response.SetBodyString(fmt.Sprintf("%v", body))
}
}
// SendBytes : https://fiber.wiki/context#sendbytes
func (ctx *Ctx) SendBytes(body []byte) {
ctx.Fasthttp.Response.SetBodyString(getString(body))
}
// SendFile : https://fiber.wiki/context#sendfile
func (ctx *Ctx) SendFile(file string, gzip ...bool) {
// Disable gzipping
if len(gzip) > 0 && !gzip[0] {
fasthttp.ServeFileUncompressed(ctx.Fasthttp, file)
return
}
fasthttp.ServeFile(ctx.Fasthttp, file)
// https://github.com/valyala/fasthttp/blob/master/fs.go#L81
//ctx.Type(filepath.Ext(path))
//ctx.Fasthttp.SendFile(path)
}
// SendStatus : https://fiber.wiki/context#sendstatus
func (ctx *Ctx) SendStatus(status int) {
ctx.Fasthttp.Response.SetStatusCode(status)
// Only set status body when there is no response body
if len(ctx.Fasthttp.Response.Body()) == 0 {
msg := getStatus(status)
if msg != "" {
ctx.Fasthttp.Response.SetBodyString(msg)
}
}
}
// SendString : https://fiber.wiki/context#sendstring
func (ctx *Ctx) SendString(body string) {
ctx.Fasthttp.Response.SetBodyString(body)
}
// Set : https://fiber.wiki/context#set
func (ctx *Ctx) Set(key string, val string) {
ctx.Fasthttp.Response.Header.SetCanonical(getBytes(key), getBytes(val))
}
// Status : https://fiber.wiki/context#status
func (ctx *Ctx) Status(status int) *Ctx {
ctx.Fasthttp.Response.SetStatusCode(status)
return ctx
}
// Type : https://fiber.wiki/context#type
func (ctx *Ctx) Type(ext string) *Ctx {
ctx.Fasthttp.Response.Header.SetContentType(getType(ext))
return ctx
}
// Vary : https://fiber.wiki/context#vary
func (ctx *Ctx) Vary(fields ...string) {
if len(fields) == 0 {
return
}
h := getString(ctx.Fasthttp.Response.Header.Peek(fasthttp.HeaderVary))
for i := range fields {
if h == "" {
h += fields[i]
} else {
h += ", " + fields[i]
}
}
ctx.Set(fasthttp.HeaderVary, h)
}
// Write : https://fiber.wiki/context#write
func (ctx *Ctx) Write(args ...interface{}) {
for i := range args {
switch body := args[i].(type) {
case string:
ctx.Fasthttp.Response.AppendBodyString(body)
case []byte:
ctx.Fasthttp.Response.AppendBodyString(getString(body))
default:
ctx.Fasthttp.Response.AppendBodyString(fmt.Sprintf("%v", body))
}
}
}
// Xml ...
func (ctx *Ctx) Xml(v interface{}) error {
return ctx.XML(v)
}
// XML will be removed in v2
func (ctx *Ctx) XML(v interface{}) error {
fmt.Println("Fiber deprecated c.XML(), this function will be removed in v2")
raw, err := xml.Marshal(v)
if err != nil {
return err
}
ctx.Fasthttp.Response.Header.SetContentType(mimeApplicationXML)
ctx.Fasthttp.Response.SetBody(raw)
return nil
}