mirror of
https://github.com/gofiber/fiber.git
synced 2025-02-22 23:24:32 +00:00
484 lines
12 KiB
Go
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
|
|
}
|