mirror of https://github.com/gofiber/fiber.git
v0.5.0
parent
a4f86dbd1e
commit
e9a4f6e360
619
context.go
619
context.go
|
@ -2,50 +2,109 @@ package fiber
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/json-iterator/go"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
// Ctx struct
|
||||
type Ctx struct {
|
||||
noCopy noCopy
|
||||
next bool
|
||||
params *[]string
|
||||
values []string
|
||||
Fasthttp *fasthttp.RequestCtx
|
||||
}
|
||||
|
||||
// Next :
|
||||
func (ctx *Ctx) Next() {
|
||||
ctx.next = true
|
||||
// Ctx pool
|
||||
var ctxPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(Ctx)
|
||||
},
|
||||
}
|
||||
|
||||
// Get new Ctx from pool
|
||||
func acquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
||||
ctx := ctxPool.Get().(*Ctx)
|
||||
ctx.Fasthttp = fctx
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Return Context to pool
|
||||
func releaseCtx(ctx *Ctx) {
|
||||
ctx.next = false
|
||||
ctx.params = nil
|
||||
ctx.values = nil
|
||||
ctx.Fasthttp = nil
|
||||
ctxPool.Put(ctx)
|
||||
}
|
||||
|
||||
// Params :
|
||||
func (ctx *Ctx) Params(key string) string {
|
||||
if ctx.params == nil {
|
||||
return ""
|
||||
// Accepts :
|
||||
func (ctx *Ctx) Accepts(ext string) bool {
|
||||
accept := ctx.Get("Accept")
|
||||
if ext[0] != '.' {
|
||||
ext = "." + ext
|
||||
}
|
||||
for i := 0; i < len(*ctx.params); i++ {
|
||||
if (*ctx.params)[i] == key {
|
||||
return ctx.values[i]
|
||||
}
|
||||
// Accept: text/*, application/json
|
||||
// n = text/html => no match
|
||||
m := mime.TypeByExtension(ext)
|
||||
if strings.Contains(accept, m) {
|
||||
return true
|
||||
}
|
||||
return ""
|
||||
// Accept: text/*, application/json
|
||||
// n = text/* => match
|
||||
m = strings.Split(m, "/")[0]
|
||||
if strings.Contains(accept, m+"/*") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Query :
|
||||
func (ctx *Ctx) Query(key string) string {
|
||||
return b2s(ctx.Fasthttp.QueryArgs().Peek(key))
|
||||
// AcceptsCharsets TODO
|
||||
func (ctx *Ctx) AcceptsCharsets() {
|
||||
|
||||
}
|
||||
|
||||
// Method :
|
||||
func (ctx *Ctx) Method() string {
|
||||
return b2s(ctx.Fasthttp.Request.Header.Method())
|
||||
// AcceptsCharsets TODO
|
||||
func (ctx *Ctx) AcceptsEncodings() {
|
||||
|
||||
}
|
||||
|
||||
// Path :
|
||||
func (ctx *Ctx) Path() string {
|
||||
return b2s(ctx.Fasthttp.URI().Path())
|
||||
// AcceptsCharsets TODO
|
||||
func (ctx *Ctx) AcceptsLanguages() {
|
||||
|
||||
}
|
||||
|
||||
// Append :
|
||||
func (ctx *Ctx) Append(field, val string) {
|
||||
prev := ctx.Get(field)
|
||||
value := val
|
||||
if prev != "" {
|
||||
value = prev + "; " + val
|
||||
}
|
||||
ctx.Set(field, value)
|
||||
}
|
||||
|
||||
// Attachment :
|
||||
func (ctx *Ctx) Attachment(name ...string) {
|
||||
if len(name) > 0 {
|
||||
filename := filepath.Base(name[0])
|
||||
ctx.Type(filepath.Ext(filename))
|
||||
ctx.Set("Content-Disposition", `attachment; filename="`+filename+`"`)
|
||||
return
|
||||
}
|
||||
ctx.Set("Content-Disposition", "attachment")
|
||||
}
|
||||
|
||||
// BaseUrl TODO
|
||||
func (ctx *Ctx) BaseUrl() {
|
||||
|
||||
}
|
||||
|
||||
// BasicAuth :
|
||||
|
@ -71,45 +130,6 @@ func (ctx *Ctx) BasicAuth() (user, pass string, ok bool) {
|
|||
return cs[:s], cs[s+1:], true
|
||||
}
|
||||
|
||||
// MultipartForm :
|
||||
func (ctx *Ctx) MultipartForm() (*multipart.Form, error) {
|
||||
return ctx.Fasthttp.MultipartForm()
|
||||
}
|
||||
|
||||
// FormValue :
|
||||
func (ctx *Ctx) FormValue(key string) string {
|
||||
return b2s(ctx.Fasthttp.FormValue(key))
|
||||
}
|
||||
|
||||
// FormFile :
|
||||
func (ctx *Ctx) FormFile(key string) (*multipart.FileHeader, error) {
|
||||
return ctx.Fasthttp.FormFile(key)
|
||||
}
|
||||
|
||||
// SaveFile :
|
||||
func (ctx *Ctx) SaveFile(fh *multipart.FileHeader, path string) {
|
||||
fasthttp.SaveMultipartFile(fh, path)
|
||||
}
|
||||
|
||||
// // FormValue :
|
||||
// func (ctx *Ctx) FormValues(key string) (values []string) {
|
||||
// form, err := ctx.Fasthttp.MultipartForm()
|
||||
// if err != nil {
|
||||
// return values
|
||||
// }
|
||||
// return form.Value[key]
|
||||
// }
|
||||
//
|
||||
// // FormFile :
|
||||
// func (ctx *Ctx) FormFiles(key string) (files []*multipart.FileHeader) {
|
||||
// form, err := ctx.Fasthttp.MultipartForm()
|
||||
// if err != nil {
|
||||
// return files
|
||||
// }
|
||||
// files = form.File[key]
|
||||
// return files
|
||||
// }
|
||||
|
||||
// Body :
|
||||
func (ctx *Ctx) Body(args ...interface{}) string {
|
||||
if len(args) == 0 {
|
||||
|
@ -130,6 +150,18 @@ func (ctx *Ctx) Body(args ...interface{}) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// ClearCookie :
|
||||
func (ctx *Ctx) ClearCookie(name ...string) {
|
||||
if len(name) == 0 {
|
||||
ctx.Fasthttp.Request.Header.VisitAllCookie(func(k, v []byte) {
|
||||
ctx.Fasthttp.Response.Header.DelClientCookie(b2s(k))
|
||||
})
|
||||
}
|
||||
if len(name) > 0 {
|
||||
ctx.Fasthttp.Response.Header.DelClientCookie(name[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Cookie :
|
||||
func (ctx *Ctx) Cookie(name, value string, options ...interface{}) {
|
||||
cook := &fasthttp.Cookie{}
|
||||
|
@ -159,16 +191,224 @@ func (ctx *Ctx) Cookies(args ...interface{}) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// ClearCookies :
|
||||
func (ctx *Ctx) ClearCookies(args ...string) {
|
||||
if len(args) == 0 {
|
||||
ctx.Fasthttp.Request.Header.VisitAllCookie(func(k, v []byte) {
|
||||
ctx.Fasthttp.Response.Header.DelClientCookie(b2s(k))
|
||||
})
|
||||
// Download :
|
||||
func (ctx *Ctx) Download(file string, name ...string) {
|
||||
filename := filepath.Base(file)
|
||||
if len(name) > 0 {
|
||||
filename = name[0]
|
||||
}
|
||||
if len(args) == 1 {
|
||||
ctx.Fasthttp.Response.Header.DelClientCookie(args[0])
|
||||
ctx.Set("Content-Disposition", "attachment; filename="+filename)
|
||||
ctx.SendFile(file)
|
||||
}
|
||||
|
||||
// End TODO
|
||||
func (ctx *Ctx) End() {
|
||||
|
||||
}
|
||||
|
||||
// Format TODO
|
||||
func (ctx *Ctx) Format() {
|
||||
|
||||
}
|
||||
|
||||
// FormFile :
|
||||
func (ctx *Ctx) FormFile(key string) (*multipart.FileHeader, error) {
|
||||
return ctx.Fasthttp.FormFile(key)
|
||||
}
|
||||
|
||||
// FormValue :
|
||||
func (ctx *Ctx) FormValue(key string) string {
|
||||
return b2s(ctx.Fasthttp.FormValue(key))
|
||||
}
|
||||
|
||||
// Fresh TODO https://expressjs.com/en/4x/api.html#req.fresh
|
||||
func (ctx *Ctx) Fresh() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Get :
|
||||
func (ctx *Ctx) Get(key string) string {
|
||||
// https://en.wikipedia.org/wiki/HTTP_referer
|
||||
if key == "referrer" {
|
||||
key = "referer"
|
||||
}
|
||||
return b2s(ctx.Fasthttp.Request.Header.Peek(key))
|
||||
}
|
||||
|
||||
// HeadersSent TODO
|
||||
func (ctx *Ctx) HeadersSent() {
|
||||
|
||||
}
|
||||
|
||||
// Hostname :
|
||||
func (ctx *Ctx) Hostname() string {
|
||||
return b2s(ctx.Fasthttp.URI().Host())
|
||||
}
|
||||
|
||||
// Ip :
|
||||
func (ctx *Ctx) Ip() string {
|
||||
return ctx.Fasthttp.RemoteIP().String()
|
||||
}
|
||||
|
||||
// Ips https://expressjs.com/en/4x/api.html#req.ips
|
||||
func (ctx *Ctx) Ips() []string {
|
||||
ips := strings.Split(ctx.Get("X-Forwarded-For"), ",")
|
||||
for i := range ips {
|
||||
ips[i] = strings.TrimSpace(ips[i])
|
||||
}
|
||||
return ips
|
||||
}
|
||||
|
||||
// Is :
|
||||
func (ctx *Ctx) Is(ext string) bool {
|
||||
if ext[0] != '.' {
|
||||
ext = "." + ext
|
||||
}
|
||||
exts, _ := mime.ExtensionsByType(ctx.Get("Content-Type"))
|
||||
if len(exts) > 0 {
|
||||
for _, item := range exts {
|
||||
if item == ext {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Json :
|
||||
func (ctx *Ctx) Json(v interface{}) error {
|
||||
raw, err := jsoniter.Marshal(&v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Set("Content-Type", "application/json")
|
||||
ctx.Fasthttp.Response.SetBodyString(b2s(raw))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Jsonp :
|
||||
func (ctx *Ctx) Jsonp(v interface{}, cb ...string) error {
|
||||
cbName := "callback"
|
||||
// Default cbName is "callback"
|
||||
if len(cb) > 0 {
|
||||
cbName = cb[0]
|
||||
}
|
||||
fmt.Println(cbName[0])
|
||||
raw, err := jsoniter.Marshal(&v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create buffer with length of json + cbname + ( );
|
||||
buf := make([]byte, len(raw)+len(cbName)+3)
|
||||
|
||||
count := 0
|
||||
count += copy(buf[count:], cbName)
|
||||
count += copy(buf[count:], "(")
|
||||
count += copy(buf[count:], raw)
|
||||
count += copy(buf[count:], ");")
|
||||
|
||||
ctx.Set("X-Content-Type-Options", "nosniff")
|
||||
ctx.Set("Content-Type", "text/javascript")
|
||||
ctx.Fasthttp.Response.SetBodyString(b2s(buf))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Links TODO
|
||||
func (ctx *Ctx) Links() {
|
||||
|
||||
}
|
||||
|
||||
// Locals TODO
|
||||
func (ctx *Ctx) Locals() {
|
||||
|
||||
}
|
||||
|
||||
// Location :
|
||||
func (ctx *Ctx) Location(path string) {
|
||||
ctx.Set("Location", path)
|
||||
}
|
||||
|
||||
// Method :
|
||||
func (ctx *Ctx) Method() string {
|
||||
return b2s(ctx.Fasthttp.Request.Header.Method())
|
||||
}
|
||||
|
||||
// MultipartForm :
|
||||
func (ctx *Ctx) MultipartForm() (*multipart.Form, error) {
|
||||
return ctx.Fasthttp.MultipartForm()
|
||||
}
|
||||
|
||||
// Next :
|
||||
func (ctx *Ctx) Next() {
|
||||
ctx.next = true
|
||||
ctx.params = nil
|
||||
ctx.values = nil
|
||||
}
|
||||
|
||||
// OriginalUrl :
|
||||
func (ctx *Ctx) OriginalUrl() string {
|
||||
return b2s(ctx.Fasthttp.Request.Header.RequestURI())
|
||||
}
|
||||
|
||||
// Params :
|
||||
func (ctx *Ctx) Params(key string) string {
|
||||
if ctx.params == nil {
|
||||
return ""
|
||||
}
|
||||
for i := 0; i < len(*ctx.params); i++ {
|
||||
if (*ctx.params)[i] == key {
|
||||
return ctx.values[i]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Path :
|
||||
func (ctx *Ctx) Path() string {
|
||||
return b2s(ctx.Fasthttp.URI().Path())
|
||||
}
|
||||
|
||||
// Protocol :
|
||||
func (ctx *Ctx) Protocol() string {
|
||||
if ctx.Fasthttp.IsTLS() {
|
||||
return "https"
|
||||
}
|
||||
return "http"
|
||||
}
|
||||
|
||||
// Query :
|
||||
func (ctx *Ctx) Query(key string) string {
|
||||
return b2s(ctx.Fasthttp.QueryArgs().Peek(key))
|
||||
}
|
||||
|
||||
// Range TODO
|
||||
func (ctx *Ctx) Range() {
|
||||
|
||||
}
|
||||
|
||||
// Redirect :
|
||||
func (ctx *Ctx) Redirect(path string, status ...int) {
|
||||
ctx.Set("Location", path)
|
||||
if len(status) > 0 {
|
||||
ctx.Status(status[0])
|
||||
} else {
|
||||
ctx.Status(302)
|
||||
}
|
||||
}
|
||||
|
||||
// Render TODO https://expressjs.com/en/4x/api.html#res.render
|
||||
func (ctx *Ctx) Render() {
|
||||
|
||||
}
|
||||
|
||||
// Route TODO https://expressjs.com/en/4x/api.html#res.render
|
||||
func (ctx *Ctx) Route() {
|
||||
|
||||
}
|
||||
|
||||
// Secure :
|
||||
func (ctx *Ctx) Secure() bool {
|
||||
return ctx.Fasthttp.IsTLS()
|
||||
}
|
||||
|
||||
// Send :
|
||||
|
@ -190,29 +430,17 @@ func (ctx *Ctx) Send(args ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// SendString internal use
|
||||
func (ctx *Ctx) SendString(body string) {
|
||||
ctx.Fasthttp.Response.SetBodyString(body)
|
||||
// SendFile :
|
||||
func (ctx *Ctx) SendFile(file string) {
|
||||
// https://github.com/valyala/fasthttp/blob/master/fs.go#L81
|
||||
fasthttp.ServeFile(ctx.Fasthttp, file)
|
||||
//ctx.Type(filepath.Ext(path))
|
||||
//ctx.Fasthttp.SendFile(path)
|
||||
}
|
||||
|
||||
// SendByte internal use
|
||||
func (ctx *Ctx) SendByte(body []byte) {
|
||||
ctx.Fasthttp.Response.SetBodyString(b2s(body))
|
||||
}
|
||||
// SendStatus :
|
||||
func (ctx *Ctx) SendStatus() {
|
||||
|
||||
// Write :
|
||||
func (ctx *Ctx) Write(args ...interface{}) {
|
||||
if len(args) != 1 {
|
||||
panic("To many arguments!")
|
||||
}
|
||||
switch body := args[0].(type) {
|
||||
case string:
|
||||
ctx.Fasthttp.Response.AppendBodyString(body)
|
||||
case []byte:
|
||||
ctx.Fasthttp.Response.AppendBodyString(b2s(body))
|
||||
default:
|
||||
panic("body must be a string or []byte")
|
||||
}
|
||||
}
|
||||
|
||||
// Set :
|
||||
|
@ -220,36 +448,14 @@ func (ctx *Ctx) Set(key string, val string) {
|
|||
ctx.Fasthttp.Response.Header.SetCanonical(s2b(key), s2b(val))
|
||||
}
|
||||
|
||||
// Get :
|
||||
func (ctx *Ctx) Get(key string) string {
|
||||
// https://en.wikipedia.org/wiki/HTTP_referer
|
||||
if key == "referrer" {
|
||||
key = "referer"
|
||||
}
|
||||
return b2s(ctx.Fasthttp.Request.Header.Peek(key))
|
||||
// SignedCookies TODO
|
||||
func (ctx *Ctx) SignedCookies() {
|
||||
|
||||
}
|
||||
|
||||
// Json :
|
||||
func (ctx *Ctx) Json(v interface{}) error {
|
||||
raw, err := json.Marshal(&v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Set("Content-Type", "application/json")
|
||||
ctx.SendByte(raw)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Redirect :
|
||||
func (ctx *Ctx) Redirect(args ...interface{}) {
|
||||
if len(args) == 1 {
|
||||
ctx.Set("Location", args[0].(string))
|
||||
ctx.Status(302)
|
||||
}
|
||||
if len(args) == 2 {
|
||||
ctx.Set("Location", args[1].(string))
|
||||
ctx.Status(args[0].(int))
|
||||
}
|
||||
// Stale TODO https://expressjs.com/en/4x/api.html#req.fresh
|
||||
func (ctx *Ctx) Stale() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Status :
|
||||
|
@ -258,6 +464,13 @@ func (ctx *Ctx) Status(status int) *Ctx {
|
|||
return ctx
|
||||
}
|
||||
|
||||
// Subdomains :
|
||||
func (ctx *Ctx) Subdomains() (subs []string) {
|
||||
subs = strings.Split(ctx.Hostname(), ".")
|
||||
subs = subs[:len(subs)-2]
|
||||
return subs
|
||||
}
|
||||
|
||||
// Type :
|
||||
func (ctx *Ctx) Type(ext string) *Ctx {
|
||||
if ext[0] != '.' {
|
||||
|
@ -268,167 +481,27 @@ func (ctx *Ctx) Type(ext string) *Ctx {
|
|||
return ctx
|
||||
}
|
||||
|
||||
// Hostname :
|
||||
func (ctx *Ctx) Hostname() string {
|
||||
return b2s(ctx.Fasthttp.URI().Host())
|
||||
// Vary TODO
|
||||
func (ctx *Ctx) Vary() {
|
||||
|
||||
}
|
||||
|
||||
// OriginalUrl :
|
||||
func (ctx *Ctx) OriginalUrl() string {
|
||||
return b2s(ctx.Fasthttp.Request.Header.RequestURI())
|
||||
}
|
||||
|
||||
// Protocol :
|
||||
func (ctx *Ctx) Protocol() string {
|
||||
if ctx.Fasthttp.IsTLS() {
|
||||
return "https"
|
||||
// Write :
|
||||
func (ctx *Ctx) Write(args ...interface{}) {
|
||||
if len(args) == 0 {
|
||||
panic("Missing body")
|
||||
}
|
||||
switch body := args[0].(type) {
|
||||
case string:
|
||||
ctx.Fasthttp.Response.SetBodyString(body)
|
||||
case []byte:
|
||||
ctx.Fasthttp.Response.AppendBodyString(b2s(body))
|
||||
default:
|
||||
panic("body must be a string or []byte")
|
||||
}
|
||||
return "http"
|
||||
}
|
||||
|
||||
// Secure :
|
||||
func (ctx *Ctx) Secure() bool {
|
||||
return ctx.Fasthttp.IsTLS()
|
||||
}
|
||||
|
||||
// Ip :
|
||||
func (ctx *Ctx) Ip() string {
|
||||
return ctx.Fasthttp.RemoteIP().String()
|
||||
}
|
||||
|
||||
// Xhr :
|
||||
func (ctx *Ctx) Xhr() bool {
|
||||
return ctx.Get("X-Requested-With") == "XMLHttpRequest"
|
||||
}
|
||||
|
||||
// Is :
|
||||
func (ctx *Ctx) Is(ext string) bool {
|
||||
if ext[0] != '.' {
|
||||
ext = "." + ext
|
||||
}
|
||||
exts, _ := mime.ExtensionsByType(ctx.Get("Content-Type"))
|
||||
if len(exts) > 0 {
|
||||
for _, item := range exts {
|
||||
if item == ext {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Attachment :
|
||||
func (ctx *Ctx) Attachment(args ...string) {
|
||||
if len(args) == 1 {
|
||||
filename := filepath.Base(args[0])
|
||||
ctx.Type(filepath.Ext(filename))
|
||||
ctx.Set("Content-Disposition", `attachment; filename="`+filename+`"`)
|
||||
return
|
||||
}
|
||||
ctx.Set("Content-Disposition", "attachment")
|
||||
}
|
||||
|
||||
// Download :
|
||||
func (ctx *Ctx) Download(args ...string) {
|
||||
if len(args) == 0 {
|
||||
panic("Missing filename")
|
||||
}
|
||||
file := args[0]
|
||||
filename := filepath.Base(file)
|
||||
if len(args) > 1 {
|
||||
filename = args[1]
|
||||
}
|
||||
ctx.Set("Content-Disposition", "attachment; filename="+filename)
|
||||
ctx.SendFile(file)
|
||||
}
|
||||
|
||||
// SendFile :
|
||||
func (ctx *Ctx) SendFile(file string) {
|
||||
// https://github.com/valyala/fasthttp/blob/master/fs.go#L81
|
||||
fasthttp.ServeFile(ctx.Fasthttp, file)
|
||||
//ctx.Type(filepath.Ext(path))
|
||||
//ctx.Fasthttp.SendFile(path)
|
||||
}
|
||||
|
||||
// Location :
|
||||
func (ctx *Ctx) Location(path string) {
|
||||
ctx.Set("Location", path)
|
||||
}
|
||||
|
||||
// Subdomains :
|
||||
func (ctx *Ctx) Subdomains() (subs []string) {
|
||||
subs = strings.Split(ctx.Hostname(), ".")
|
||||
subs = subs[:len(subs)-2]
|
||||
return subs
|
||||
}
|
||||
|
||||
// Ips https://expressjs.com/en/4x/api.html#req.ips
|
||||
func (ctx *Ctx) Ips() []string {
|
||||
ips := strings.Split(ctx.Get("X-Forwarded-For"), " ")
|
||||
return ips
|
||||
}
|
||||
|
||||
// Jsonp TODO https://expressjs.com/en/4x/api.html#res.jsonp
|
||||
func (ctx *Ctx) Jsonp(args ...interface{}) error {
|
||||
jsonp := "callback("
|
||||
if len(args) == 1 {
|
||||
raw, err := json.Marshal(&args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
jsonp += b2s(raw) + ");"
|
||||
} else if len(args) == 2 {
|
||||
jsonp = args[0].(string) + "("
|
||||
raw, err := json.Marshal(&args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
jsonp += b2s(raw) + ");"
|
||||
} else {
|
||||
panic("Missing interface{}")
|
||||
}
|
||||
ctx.Set("X-Content-Type-Options", "nosniff")
|
||||
ctx.Set("Content-Type", "text/javascript")
|
||||
ctx.SendString(jsonp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Vary TODO https://expressjs.com/en/4x/api.html#res.vary
|
||||
func (ctx *Ctx) Vary() {
|
||||
|
||||
}
|
||||
|
||||
// Links TODO https://expressjs.com/en/4x/api.html#res.links
|
||||
func (ctx *Ctx) Links() {
|
||||
|
||||
}
|
||||
|
||||
// Append TODO https://expressjs.com/en/4x/api.html#res.append
|
||||
func (ctx *Ctx) Append(field, val string) {
|
||||
prev := ctx.Get(field)
|
||||
value := val
|
||||
if prev != "" {
|
||||
value = prev + "; " + val
|
||||
}
|
||||
ctx.Set(field, value)
|
||||
}
|
||||
|
||||
// Accepts TODO https://expressjs.com/en/4x/api.html#req.accepts
|
||||
func (ctx *Ctx) Accepts() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Range TODO https://expressjs.com/en/4x/api.html#req.range
|
||||
func (ctx *Ctx) Range() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Fresh TODO https://expressjs.com/en/4x/api.html#req.fresh
|
||||
func (ctx *Ctx) Fresh() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Stale TODO https://expressjs.com/en/4x/api.html#req.fresh
|
||||
func (ctx *Ctx) Stale() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,164 +1,59 @@
|
|||
# Application
|
||||
The app object conventionally denotes the Fiber application.
|
||||
|
||||
## Initialize
|
||||
#### Initialize
|
||||
Creates an Fiber instance name "app"
|
||||
```go
|
||||
app := fiber.New()
|
||||
// Optional fiber settings
|
||||
// Sends the "Server" header, disabled by default
|
||||
app.Server = ""
|
||||
// Clears console when launched, disabled by default
|
||||
app.ClearConsole = false
|
||||
// Hides fiber banner, enabled by default
|
||||
app.NoBanner = false
|
||||
```
|
||||
|
||||
## Settings
|
||||
You can pass some [Fasthttp server settings](https://github.com/valyala/fasthttp/blob/master/server.go#L150) via the Fiber instance.
|
||||
Make sure that you set these settings before calling the [Listen](#listen) method.
|
||||
#### TLS
|
||||
To enable TLS you need to provide a certkey and certfile.
|
||||
```go
|
||||
// Enable TLS
|
||||
app := fiber.New()
|
||||
|
||||
app.CertKey("./cert.key")
|
||||
app.CertFile("./cert.pem")
|
||||
|
||||
app.Listen(443)
|
||||
```
|
||||
#### Fasthttp
|
||||
You can pass some Fasthttp server settings via the Fiber instance.
|
||||
Make sure that you set these settings before calling the [Listen](#listen) method. You can find the description of each property in [Fasthttp server settings](https://github.com/valyala/fasthttp/blob/master/server.go#L150)
|
||||
|
||||
!>Only change these settings if you know what you are doing.
|
||||
```go
|
||||
app := fiber.New()
|
||||
|
||||
// Server name for sending in response headers.
|
||||
//
|
||||
// No server header is send if left empty.
|
||||
app.Name = ""
|
||||
|
||||
// Clears the console when you run app
|
||||
app.ClearConsole = false
|
||||
|
||||
// Hides the "Fiber" banner when you launch your application.
|
||||
app.HideBanner = false
|
||||
|
||||
// Enables TLS, you need to provide a certificate key and file
|
||||
app.TLSEnable = false
|
||||
|
||||
// Cerficate key
|
||||
app.CertKey = ""
|
||||
|
||||
// Certificate file
|
||||
app.CertFile = ""
|
||||
|
||||
// The maximum number of concurrent connections the server may serve.
|
||||
app.Concurrency = 256 * 1024
|
||||
|
||||
// Whether to disable keep-alive connections.
|
||||
//
|
||||
// The server will close all the incoming connections after sending
|
||||
// the first response to client if this option is set to true.
|
||||
//
|
||||
// By default keep-alive connections are enabled.
|
||||
app.DisableKeepAlive = false
|
||||
|
||||
// Per-connection buffer size for requests' reading.
|
||||
// This also limits the maximum header size.
|
||||
//
|
||||
// Increase this buffer if your clients send multi-KB RequestURIs
|
||||
// and/or multi-KB headers (for example, BIG cookies).
|
||||
app.ReadBufferSize = 4096
|
||||
|
||||
// Per-connection buffer size for responses' writing.
|
||||
app.WriteBufferSize = 4096
|
||||
|
||||
// ReadTimeout is the amount of time allowed to read
|
||||
// the full request including body. The connection's read
|
||||
// deadline is reset when the connection opens, or for
|
||||
// keep-alive connections after the first byte has been read.
|
||||
//
|
||||
// By default request read timeout is unlimited.
|
||||
app.ReadTimeout = 0
|
||||
|
||||
// WriteTimeout is the maximum duration before timing out
|
||||
// writes of the response. It is reset after the request handler
|
||||
// has returned.
|
||||
//
|
||||
// By default response write timeout is unlimited.
|
||||
app.WriteTimeout = 0
|
||||
|
||||
// IdleTimeout is the maximum amount of time to wait for the
|
||||
// next request when keep-alive is enabled. If IdleTimeout
|
||||
// is zero, the value of ReadTimeout is used.
|
||||
app.IdleTimeout = 0
|
||||
|
||||
// Maximum number of concurrent client connections allowed per IP.
|
||||
//
|
||||
// By default unlimited number of concurrent connections
|
||||
// may be established to the server from a single IP address.
|
||||
app.MaxConnsPerIP = 0
|
||||
|
||||
// Maximum number of requests served per connection.
|
||||
//
|
||||
// The server closes connection after the last request.
|
||||
// 'Connection: close' header is added to the last response.
|
||||
//
|
||||
// By default unlimited number of requests may be served per connection.
|
||||
app.MaxRequestsPerConn = 0
|
||||
|
||||
// Whether to enable tcp keep-alive connections.
|
||||
//
|
||||
// Whether the operating system should send tcp keep-alive messages on the tcp connection.
|
||||
//
|
||||
// By default tcp keep-alive connections are disabled.
|
||||
app.TCPKeepalive = false
|
||||
|
||||
// Period between tcp keep-alive messages.
|
||||
//
|
||||
// TCP keep-alive period is determined by operation system by default.
|
||||
app.TCPKeepalivePeriod = 0
|
||||
|
||||
// Maximum request body size.
|
||||
//
|
||||
// The server rejects requests with bodies exceeding this limit.
|
||||
//
|
||||
// Request body size is limited by DefaultMaxRequestBodySize by default.
|
||||
app.MaxRequestBodySize = 4 * 1024 * 1024
|
||||
|
||||
// Aggressively reduces memory usage at the cost of higher CPU usage
|
||||
// if set to true.
|
||||
//
|
||||
// Try enabling this option only if the server consumes too much memory
|
||||
// serving mostly idle keep-alive connections. This may reduce memory
|
||||
// usage by more than 50%.
|
||||
//
|
||||
// Aggressive memory usage reduction is disabled by default.
|
||||
app.ReduceMemoryUsage = false
|
||||
|
||||
// Rejects all non-GET requests if set to true.
|
||||
//
|
||||
// This option is useful as anti-DoS protection for servers
|
||||
// accepting only GET requests. The request size is limited
|
||||
// by ReadBufferSize if GetOnly is set.
|
||||
//
|
||||
// Server accepts all the requests by default.
|
||||
app.GetOnly = false
|
||||
|
||||
// By default request and response header names are normalized, i.e.
|
||||
// The first letter and the first letters following dashes
|
||||
// are uppercased, while all the other letters are lowercased.
|
||||
// Examples:
|
||||
//
|
||||
// * HOST -> Host
|
||||
// * content-type -> Content-Type
|
||||
// * cONTENT-lenGTH -> Content-Length
|
||||
app.DisableHeaderNamesNormalizing = false
|
||||
|
||||
// SleepWhenConcurrencyLimitsExceeded is a duration to be slept of if
|
||||
// the concurrency limit in exceeded (default [when is 0]: don't sleep
|
||||
// and accept new connections immidiatelly).
|
||||
app.SleepWhenConcurrencyLimitsExceeded = 0
|
||||
|
||||
// NoDefaultContentType, when set to true, causes the default Content-Type
|
||||
// header to be excluded from the Response.
|
||||
//
|
||||
// The default Content-Type header value is the internal default value. When
|
||||
// set to true, the Content-Type will not be present.
|
||||
app.NoDefaultContentType = false
|
||||
|
||||
// KeepHijackedConns is an opt-in disable of connection
|
||||
// close by fasthttp after connections' HijackHandler returns.
|
||||
// This allows to save goroutines, e.g. when fasthttp used to upgrade
|
||||
// http connections to WS and connection goes to another handler,
|
||||
// which will close it when needed.
|
||||
app.KeepHijackedConns = false
|
||||
app.Fasthttp.Concurrency = 256 * 1024
|
||||
app.Fasthttp.DisableKeepAlive = false
|
||||
app.Fasthttp.ReadBufferSize = 4096
|
||||
app.Fasthttp.WriteBufferSize = 4096
|
||||
app.Fasthttp.ReadTimeout = 0
|
||||
app.Fasthttp.WriteTimeout = 0
|
||||
app.Fasthttp.IdleTimeout = 0
|
||||
app.Fasthttp.MaxConnsPerIP = 0
|
||||
app.Fasthttp.MaxRequestsPerConn = 0
|
||||
app.Fasthttp.TCPKeepalive = false
|
||||
app.Fasthttp.TCPKeepalivePeriod = 0
|
||||
app.Fasthttp.MaxRequestBodySize = 4 * 1024 * 1024
|
||||
app.Fasthttp.ReduceMemoryUsage = false
|
||||
app.Fasthttp.GetOnly = false
|
||||
app.Fasthttp.DisableHeaderNamesNormalizing = false
|
||||
app.Fasthttp.SleepWhenConcurrencyLimitsExceeded = 0
|
||||
app.Fasthttp.NoDefaultContentType = false
|
||||
app.Fasthttp.KeepHijackedConns = false
|
||||
```
|
||||
|
||||
## Methods
|
||||
#### Methods
|
||||
Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, PUT, POST, and so on capitalized. Thus, the actual methods are app.Get(), app.Post(), app.Put(), and so on. See Routing methods below for the complete list.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -176,7 +71,7 @@ app.Use(...)
|
|||
app.All(...)
|
||||
```
|
||||
|
||||
## Listen
|
||||
#### Listen
|
||||
Binds and listens for connections on the specified host and port.
|
||||
```go
|
||||
// Function signature
|
||||
|
|
189
docs/context.md
189
docs/context.md
|
@ -1,10 +1,19 @@
|
|||
# Context
|
||||
The ctx object represents the HTTP request and response and has methods for the request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, the context is always referred to as c but its actual name is determined by the parameters to the callback function in which you’re working.
|
||||
|
||||
## Accepts
|
||||
!> Planned for V2
|
||||
#### Accepts
|
||||
!> Planned for V1
|
||||
|
||||
## Append
|
||||
#### AcceptsCharsets
|
||||
!> Planned for V1
|
||||
|
||||
#### AcceptsEncodings
|
||||
!> Planned for V1
|
||||
|
||||
#### AcceptsLanguages
|
||||
!> Planned for V1
|
||||
|
||||
#### Append
|
||||
Appends the specified value to the HTTP response header field. If the header is not already set, it creates the header with the specified value. The value parameter must be a string.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -25,8 +34,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
|
||||
## Attachment
|
||||
#### Attachment
|
||||
Sets the HTTP response [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header field to “attachment”. If a filename is given, then it sets the Content-Type based on the extension name via (Type)[#type], and sets the Content-Disposition “filename=” parameter.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -44,7 +52,10 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## BasicAuth
|
||||
#### BaseUrl
|
||||
!> Planned for V1
|
||||
|
||||
#### BasicAuth
|
||||
BasicAuth returns the username and password provided in the request's Authorization header, if the request uses [HTTP Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -65,8 +76,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
|
||||
## Body
|
||||
#### Body
|
||||
Contains the raw post body submitted in the request.
|
||||
Calling a key in body returns a string value if exist or you loop trough the body params using a key value function callback.
|
||||
|
||||
|
@ -96,24 +106,24 @@ app.Post("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## ClearCookies
|
||||
#### ClearCookie
|
||||
Clears all client cookies or a specific cookie by name by setting the expire date in the past.
|
||||
```go
|
||||
// Function signature
|
||||
c.ClearCookies()
|
||||
c.ClearCookies(key string)
|
||||
c.ClearCookie()
|
||||
c.ClearCookie(key string)
|
||||
|
||||
// Example
|
||||
app.Get("/", func(c *fiber.Ctx) {
|
||||
// Expires all cookies
|
||||
c.ClearCookies()
|
||||
c.ClearCookie()
|
||||
|
||||
// Expire specific cookie
|
||||
c.ClearCookies("user")
|
||||
c.ClearCookie("user")
|
||||
})
|
||||
```
|
||||
|
||||
## Cookie
|
||||
#### Cookie
|
||||
Sets cookie name to value, the third options parameter is not implemented yet.
|
||||
```go
|
||||
c.Cookie(name, value string)
|
||||
|
@ -128,7 +138,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
|
||||
```
|
||||
|
||||
## Cookies
|
||||
#### Cookies
|
||||
Get and set cookies
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -154,7 +164,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Download
|
||||
#### Download
|
||||
Transfers the file at path as an “attachment”. Typically, browsers will prompt the user for download. By default, the Content-Disposition header “filename=” parameter is path (this typically appears in the browser dialog). Override this default with the filename parameter.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -171,7 +181,10 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Fasthttp
|
||||
#### End
|
||||
!> Planned for V1
|
||||
|
||||
#### Fasthttp
|
||||
You can still access and use all Fasthttp methods and properties.
|
||||
Please read the [Fasthttp Documentation](https://godoc.org/github.com/valyala/fasthttp) for more information
|
||||
```go
|
||||
|
@ -188,7 +201,10 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## FormFile
|
||||
#### Format
|
||||
!> Planned for V1
|
||||
|
||||
#### FormFile
|
||||
MultipartForm files can be retrieved by name, the first file from the given key is returned.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -207,7 +223,7 @@ app.Post("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## FormValue
|
||||
#### FormValue
|
||||
MultipartForm values can be retrieved by name, the first value from the given key is returned.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -221,8 +237,10 @@ app.Post("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
#### Fresh
|
||||
!> Planned for V1
|
||||
|
||||
## Get
|
||||
#### Get
|
||||
Returns the HTTP response header specified by field. The match is case-insensitive.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -241,7 +259,10 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Hostname
|
||||
#### HeadersSent
|
||||
!> Planned for V1
|
||||
|
||||
#### Hostname
|
||||
Contains the hostname derived from the Host HTTP header.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -255,7 +276,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Ip
|
||||
#### Ip
|
||||
Contains the remote IP address of the request.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -268,7 +289,21 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Is
|
||||
#### Ips
|
||||
contains an array of IP addresses specified in the X-Forwarded-For request header.
|
||||
```go
|
||||
// Function signature
|
||||
c.Ips() []string
|
||||
|
||||
// Example
|
||||
// X-Forwarded-For: proxy1, 127.0.0.1", proxy3
|
||||
app.Get("/", func(c *fiber.Ctx) {
|
||||
c.Ips()
|
||||
// => ["proxy1", "127.0.0.1", "proxy3"]
|
||||
})
|
||||
```
|
||||
|
||||
#### Is
|
||||
Returns the matching content type if the incoming request’s “Content-Type” HTTP header field matches the MIME type specified by the type parameter. If the request has no body, returns false.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -288,8 +323,8 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Json
|
||||
Converts any interface to json using [FFJson](https://github.com/pquerna/ffjson), this functions also sets the content header to application/json.
|
||||
#### Json
|
||||
Converts any interface to json using [Jsoniter](https://github.com/json-iterator/go), this functions also sets the content header to application/json.
|
||||
```go
|
||||
// Function signature
|
||||
c.Json(v interface{}) error
|
||||
|
@ -319,7 +354,7 @@ app.Get("/json", func(c *fiber.Ctx) {
|
|||
app.Listen(8080)
|
||||
```
|
||||
|
||||
## Jsonp
|
||||
#### Jsonp
|
||||
Sends a JSON response with JSONP support. This method is identical to [Json()](#json), except that it opts-in to JSONP callback support.
|
||||
|
||||
By default, the JSONP callback name is simply callback. Override this by passing a named string in the function.
|
||||
|
@ -348,7 +383,26 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
app.Listen(8080)
|
||||
```
|
||||
|
||||
## Method
|
||||
#### Links
|
||||
!> Planned for V1
|
||||
|
||||
#### Locals
|
||||
!> Planned for V1
|
||||
|
||||
#### Location
|
||||
Sets the response Location HTTP header to the specified path parameter.
|
||||
```go
|
||||
// Function signature
|
||||
c.Location(path string)
|
||||
|
||||
// Example
|
||||
app.Post("/", func(c *fiber.Ctx) {
|
||||
c.Location("http://example.com")
|
||||
c.Location("/foo/bar")
|
||||
})
|
||||
```
|
||||
|
||||
#### Method
|
||||
Contains a string corresponding to the HTTP method of the request: GET, POST, PUT, and so on.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -361,7 +415,7 @@ app.Post("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## MultipartForm
|
||||
#### MultipartForm
|
||||
To access multipart form entries, you can parse the binary with .MultipartForm().
|
||||
This returns a map[string][]string, so given a key the value will be a string slice.
|
||||
So accepting multiple files or values is easy, as shown below!
|
||||
|
@ -396,7 +450,7 @@ app.Post("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Next
|
||||
#### Next
|
||||
When Next() is called, it executes the next function in the stack that matches the current route.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -417,7 +471,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## OriginalUrl
|
||||
#### OriginalUrl
|
||||
Contains the original request URL.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -431,7 +485,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Params
|
||||
#### Params
|
||||
This method can be used to get the route parameters. For example, if you have the route /user/:name, then the “name” property is available as c.Params("name"). This method defaults "".
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -445,7 +499,7 @@ app.Get("/user/:name", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Path
|
||||
#### Path
|
||||
Contains the path part of the request URL.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -459,7 +513,7 @@ app.Get("/users", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Protocol
|
||||
#### Protocol
|
||||
Contains the request protocol string: either http or (for TLS requests) https.
|
||||
|
||||
```go
|
||||
|
@ -472,7 +526,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
// => "http"
|
||||
})
|
||||
```
|
||||
## Query
|
||||
#### Query
|
||||
This property is an object containing a property for each query string parameter in the route. If there is no query string, it returns an empty string
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -489,7 +543,11 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
// => "desc"
|
||||
})
|
||||
```
|
||||
## Redirect
|
||||
|
||||
#### Range
|
||||
!> Planned for V1
|
||||
|
||||
#### Redirect
|
||||
Redirects to the URL derived from the specified path, with specified status, a positive integer that corresponds to an HTTP status code . If not specified, status defaults to “302 “Found”.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -505,7 +563,13 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## SaveFile
|
||||
#### Render
|
||||
!> Planned for V1
|
||||
|
||||
#### Route
|
||||
!> Planned for V1
|
||||
|
||||
#### SaveFile
|
||||
This function is used to save any multipart file to disk.
|
||||
You can see a working example here: [Multiple file upload](#multipartform)
|
||||
|
||||
|
@ -514,7 +578,18 @@ You can see a working example here: [Multiple file upload](#multipartform)
|
|||
c.SaveFile(fh *multipart.FileHeader, path string)
|
||||
```
|
||||
|
||||
## Send
|
||||
#### Secure
|
||||
A Boolean property that is true if a TLS connection is established.
|
||||
|
||||
```go
|
||||
// Function signature
|
||||
c.Secure() bool
|
||||
|
||||
// Equivalent to:
|
||||
c.Protocol() == "https"
|
||||
```
|
||||
|
||||
#### Send
|
||||
Sends the HTTP response.
|
||||
|
||||
The Send parameter can be a buffer or string
|
||||
|
@ -530,7 +605,8 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
c.Send([]byte("Hello, World!"))
|
||||
})
|
||||
```
|
||||
## SendFile
|
||||
|
||||
#### SendFile
|
||||
Transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename’s extension.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -542,7 +618,10 @@ app.Get("/not-found", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Set
|
||||
#### SendStatus
|
||||
!> Planned for V1
|
||||
|
||||
#### Set
|
||||
Sets the response’s HTTP header field to value. To set multiple fields at once, pass an object as the parameter.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -555,7 +634,13 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Status
|
||||
#### SignedCookies
|
||||
!> Planned for V1
|
||||
|
||||
#### Stale
|
||||
!> Planned for V1
|
||||
|
||||
#### Status
|
||||
Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -569,7 +654,22 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Type
|
||||
#### Subdomains
|
||||
An array of subdomains in the domain name of the request.
|
||||
The application property subdomain offset, which defaults to 2, is used for determining the beginning of the subdomain segments.
|
||||
```go
|
||||
// Function signature
|
||||
c.Subdomains() []string
|
||||
|
||||
// Example
|
||||
// Host: "tobi.ferrets.example.com"
|
||||
app.Get("/", func(c *fiber.Ctx) {
|
||||
c.Subdomains(200)
|
||||
// => ["ferrets", "tobi"]
|
||||
})
|
||||
```
|
||||
|
||||
#### Type
|
||||
Sets the Content-Type HTTP header to the MIME type as determined by mime.lookup() for the specified type. If type contains the “/” character, then it sets the Content-Type to type.
|
||||
```go
|
||||
// Function signature
|
||||
|
@ -591,7 +691,10 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Write
|
||||
#### Vary
|
||||
!> Planned for V1
|
||||
|
||||
#### Write
|
||||
Appends to the HTTP response.
|
||||
|
||||
The Write parameter can be a buffer or string
|
||||
|
@ -614,7 +717,7 @@ app.Get("/", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Xhr
|
||||
#### Xhr
|
||||
A Boolean property that is true if the request’s **X-Requested-With** header field is **XMLHttpRequest**, indicating that the request was issued by a client library such as [jQuery](https://api.jquery.com/jQuery.ajax/).
|
||||
```go
|
||||
// Function signature
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Examples
|
||||
|
||||
## Multiple File Upload
|
||||
#### Multiple File Upload
|
||||
```go
|
||||
|
||||
package main
|
||||
|
@ -31,7 +31,7 @@ func main() {
|
|||
app.Listen(8080)
|
||||
}
|
||||
```
|
||||
## 404 Handling
|
||||
#### 404 Handling
|
||||
```go
|
||||
package main
|
||||
|
||||
|
@ -50,7 +50,7 @@ func notFound(c *fiber.Ctx) {
|
|||
c.Status(404).Send("Not Found")
|
||||
}
|
||||
```
|
||||
## Static Caching
|
||||
#### Static Caching
|
||||
```go
|
||||
package main
|
||||
|
||||
|
@ -68,7 +68,7 @@ func cacheControl(c *fiber.Ctx) {
|
|||
c.Next()
|
||||
}
|
||||
```
|
||||
## Enable CORS
|
||||
#### Enable CORS
|
||||
```go
|
||||
package main
|
||||
|
||||
|
@ -92,7 +92,7 @@ func apiHandler(c *fiber.Ctx) {
|
|||
c.Send("Hi, I'm API!")
|
||||
}
|
||||
```
|
||||
## Returning JSON
|
||||
#### Returning JSON
|
||||
```go
|
||||
package main
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
Accepts
|
||||
AcceptsCharsets
|
||||
AcceptsEncodings
|
||||
AcceptsLanguages
|
||||
Append
|
||||
Attachment
|
||||
BaseUrl
|
||||
BasicAuth
|
||||
Body
|
||||
ClearCookie
|
||||
Cookie
|
||||
Cookies
|
||||
Download
|
||||
End
|
||||
Format
|
||||
FormFile
|
||||
FormValue
|
||||
Fresh
|
||||
Get
|
||||
HeadersSent
|
||||
Hostname
|
||||
Ip
|
||||
Ips
|
||||
Is
|
||||
Json
|
||||
Jsonp
|
||||
Links
|
||||
Locals
|
||||
Location
|
||||
Method
|
||||
MultipartForm
|
||||
Next
|
||||
OriginalUrl
|
||||
Params
|
||||
Path
|
||||
Protocol
|
||||
Query
|
||||
Range
|
||||
Redirect
|
||||
Render
|
||||
Route
|
||||
SaveFile
|
||||
Secure
|
||||
Send
|
||||
SendFile
|
||||
SendStatus
|
||||
Set
|
||||
Write
|
||||
SignedCookies
|
||||
Stale
|
||||
Status
|
||||
Subdomains
|
||||
Type
|
||||
Vary
|
||||
Xhr
|
|
@ -9,13 +9,13 @@
|
|||
**[Fiber](https://github.com/fenny/fiber)** is a router framework build on top of [FastHTTP](https://github.com/valyala/fasthttp), the fastest HTTP package for **[Go](https://golang.org/doc/)**.<br>
|
||||
This library is inspired by [Express](https://expressjs.com/en/4x/api.html), one of the most populair and well known web framework for **[Nodejs](https://nodejs.org/en/about/)**.
|
||||
|
||||
## Installing
|
||||
#### Installing
|
||||
Assuming you’ve already installed [Go](https://golang.org/doc/), install the [Fiber](https://github.com/fenny/fiber) package by calling the following command:
|
||||
```shell
|
||||
$ go get -u github.com/fenny/fiber
|
||||
```
|
||||
|
||||
## Hello world
|
||||
#### Hello world
|
||||
Embedded below is essentially the simplest Fiber app you can create.
|
||||
```shell
|
||||
$ create server.go
|
||||
|
@ -38,7 +38,7 @@ $ go run server.go
|
|||
```
|
||||
Browse to http://localhost:8080 and you should see Hello, World! on the page.
|
||||
|
||||
## Basic routing
|
||||
#### Basic routing
|
||||
Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
|
||||
|
||||
Each route can have one handler function, that is executed when the route is matched.
|
||||
|
@ -84,7 +84,7 @@ app.Delete("/user", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Static files
|
||||
#### Static files
|
||||
To serve static files such as images, CSS files, and JavaScript files, replace your function handler with a file or directory string.
|
||||
```go
|
||||
// Function signature
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'Fiber',
|
||||
name: 'Fiber v0.5.0',
|
||||
repo: 'fenny/fiber',
|
||||
loadSidebar: "sidebar.md",
|
||||
homepage: 'getting_started.md',
|
||||
subMaxLevel: 2,
|
||||
subMaxLevel: 4,
|
||||
auto2top: true
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Routing
|
||||
|
||||
|
||||
## Paths
|
||||
#### Paths
|
||||
Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expressions.
|
||||
|
||||
The characters ?, +, "8", and () are subsets of their regular expression counterparts. The hyphen (-) and the dot (.) are interpreted literally by string-based paths.
|
||||
|
@ -47,7 +47,7 @@ app.Get("/ab(cd)?e", func(c *fiber.Ctx) {
|
|||
})
|
||||
```
|
||||
|
||||
## Parameters
|
||||
#### Parameters
|
||||
Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values can be retrieved using the [Params](context#params) function, with the name of the route parameter specified in the path as their respective keys.
|
||||
|
||||
To define routes with route parameters, simply specify the route parameters in the path of the route as shown below.
|
||||
|
@ -70,7 +70,7 @@ app.Get("/user/:name?", func(c *fiber.Ctx) {
|
|||
|
||||
!> The hyphen (-) and the dot (.) are not interpreted literally yet, planned for V2
|
||||
|
||||
## Middleware
|
||||
#### Middleware
|
||||
The [Next](context#next) function is a function in the [Fiber](https://github.com/fenny/fiber) router which, when called, executes the next function that matches the current route.
|
||||
|
||||
Functions that are designed to make changes to the request or response are called middleware functions.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- [Getting Started](/ "Fiber - Getting Started")
|
||||
- [Application](application.md "Fiber - Application")
|
||||
- [Routing](routing.md "Fiber - Routing")
|
||||
- [Context](context.md "Fiber - Context")
|
||||
- [Routing](routing.md "Fiber - Routing")
|
||||
- [Examples](examples.md "Fiber - Examples")
|
||||
- [License](license.md "Fiber - License")
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
module github.com/fenny/fiber
|
||||
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
github.com/json-iterator/go v1.1.9
|
||||
github.com/valyala/fasthttp v1.7.1
|
||||
)
|
|
@ -0,0 +1,25 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.7.1 h1:UHtt5/7O70RSUZTR/hSu0PNWMAfWx5AtsPp9Jk+g17M=
|
||||
github.com/valyala/fasthttp v1.7.1/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
38
pool.go
38
pool.go
|
@ -1,38 +0,0 @@
|
|||
package fiber
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// Context struct
|
||||
type Ctx struct {
|
||||
next bool
|
||||
params *[]string
|
||||
values []string
|
||||
Fasthttp *fasthttp.RequestCtx
|
||||
}
|
||||
|
||||
// Context pool
|
||||
var ctxPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(Ctx)
|
||||
},
|
||||
}
|
||||
|
||||
// Get new Context from pool
|
||||
func acquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
||||
ctx := ctxPool.Get().(*Ctx)
|
||||
ctx.Fasthttp = fctx
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Return Context to pool
|
||||
func releaseCtx(ctx *Ctx) {
|
||||
ctx.next = false
|
||||
ctx.params = nil
|
||||
ctx.values = nil
|
||||
ctx.Fasthttp = nil
|
||||
ctxPool.Put(ctx)
|
||||
}
|
245
router.go
245
router.go
|
@ -11,38 +11,69 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
// ParseJSON "github.com/tidwall/gjson"
|
||||
// This json parsing lib is awesome *.*
|
||||
// "github.com/tidwall/gjson"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
const (
|
||||
Version = `v0.4.0`
|
||||
banner = ` _____ _ _
|
||||
| __|_| |_ ___ ___
|
||||
| __| | . | -_| _|
|
||||
|__| |_|___|___|_|%s %s
|
||||
// Version for debugging
|
||||
Version = `0.5.0`
|
||||
// Port and Version are printed with the banner
|
||||
banner = `%s _____ _ _
|
||||
| __|_| |_ ___ ___
|
||||
| __| | . | -_| _|
|
||||
|__| |_|___|___|_|%s
|
||||
%s%s
|
||||
|
||||
`
|
||||
`
|
||||
// https://play.golang.org/p/r6GNeV1gbH
|
||||
cReset = "\x1b[0000m"
|
||||
cBlack = "\x1b[1;30m"
|
||||
cRed = "\x1b[1;31m"
|
||||
cGreen = "\x1b[1;32m"
|
||||
cYellow = "\x1b[1;33m"
|
||||
cBlue = "\x1b[1;34m"
|
||||
cMagenta = "\x1b[1;35m"
|
||||
cCyan = "\x1b[1;36m"
|
||||
cWhite = "\x1b[1;37m"
|
||||
)
|
||||
|
||||
// Fiber structure
|
||||
type Fiber struct {
|
||||
// Stores all routes
|
||||
routes []*route
|
||||
// Fasthttp server settings
|
||||
Fasthttp *Fasthttp
|
||||
// Server name header
|
||||
Server string
|
||||
// Provide certificate files to enable TLS
|
||||
CertKey string
|
||||
CertFile string
|
||||
// Disable the fiber banner on launch
|
||||
NoBanner bool
|
||||
// Clears terminal on launch
|
||||
ClearTerminal bool
|
||||
}
|
||||
|
||||
type route struct {
|
||||
method string
|
||||
any bool
|
||||
path string
|
||||
regex *regexp.Regexp
|
||||
params []string
|
||||
// HTTP method in uppercase, can be a * for Use() & All()
|
||||
method string
|
||||
// Any bool is for routes without a path or * and /*
|
||||
any bool
|
||||
// Stores the orignal path
|
||||
path string
|
||||
// Stores compiled regex special routes :params, *wildcards, optionals?
|
||||
regex *regexp.Regexp
|
||||
// Store params if special routes :params, *wildcards, optionals?
|
||||
params []string
|
||||
// Callback function for specific route
|
||||
handler func(*Ctx)
|
||||
}
|
||||
|
||||
// Settings :
|
||||
type Settings struct {
|
||||
Name string
|
||||
ClearTerminal bool
|
||||
HideBanner bool
|
||||
TLSEnable bool
|
||||
CertKey string
|
||||
CertFile string
|
||||
// Fasthttp settings
|
||||
// https://github.com/valyala/fasthttp/blob/master/server.go#L150
|
||||
type Fasthttp struct {
|
||||
Concurrency int
|
||||
DisableKeepAlive bool
|
||||
ReadBufferSize int
|
||||
|
@ -59,27 +90,25 @@ type Settings struct {
|
|||
GetOnly bool
|
||||
DisableHeaderNamesNormalizing bool
|
||||
SleepWhenConcurrencyLimitsExceeded time.Duration
|
||||
NoDefaultServerHeader bool
|
||||
NoDefaultContentType bool
|
||||
KeepHijackedConns bool
|
||||
}
|
||||
|
||||
// Fiber :
|
||||
type Fiber struct {
|
||||
routes []*route
|
||||
Settings *Settings
|
||||
}
|
||||
|
||||
// New :
|
||||
// New creates a Fiber instance
|
||||
func New() *Fiber {
|
||||
return &Fiber{
|
||||
Settings: &Settings{
|
||||
Name: "",
|
||||
ClearTerminal: false,
|
||||
HideBanner: false,
|
||||
TLSEnable: false,
|
||||
CertKey: "",
|
||||
CertFile: "",
|
||||
// No server header is sent when set empty ""
|
||||
Server: "",
|
||||
// TLS is disabled by default, unless files are provided
|
||||
CertKey: "",
|
||||
CertFile: "",
|
||||
// Fiber banner is printed by default
|
||||
NoBanner: false,
|
||||
// Terminal is not cleared by default
|
||||
ClearTerminal: false,
|
||||
Fasthttp: &Fasthttp{
|
||||
// Default fasthttp settings
|
||||
// https://github.com/valyala/fasthttp/blob/master/server.go#L150
|
||||
Concurrency: 256 * 1024,
|
||||
DisableKeepAlive: false,
|
||||
ReadBufferSize: 4096,
|
||||
|
@ -96,68 +125,76 @@ func New() *Fiber {
|
|||
GetOnly: false,
|
||||
DisableHeaderNamesNormalizing: false,
|
||||
SleepWhenConcurrencyLimitsExceeded: 0,
|
||||
NoDefaultServerHeader: true,
|
||||
NoDefaultContentType: false,
|
||||
KeepHijackedConns: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Connect :
|
||||
// Connect establishes a tunnel to the server
|
||||
// identified by the target resource.
|
||||
func (r *Fiber) Connect(args ...interface{}) {
|
||||
r.register("CONNECT", args...)
|
||||
}
|
||||
|
||||
// Put :
|
||||
// Put replaces all current representations
|
||||
// of the target resource with the request payload.
|
||||
func (r *Fiber) Put(args ...interface{}) {
|
||||
r.register("PUT", args...)
|
||||
}
|
||||
|
||||
// Post :
|
||||
// Post is used to submit an entity to the specified resource,
|
||||
// often causing a change in state or side effects on the server.
|
||||
func (r *Fiber) Post(args ...interface{}) {
|
||||
r.register("POST", args...)
|
||||
}
|
||||
|
||||
// Delete :
|
||||
// Delete deletes the specified resource.
|
||||
func (r *Fiber) Delete(args ...interface{}) {
|
||||
r.register("DELETE", args...)
|
||||
}
|
||||
|
||||
// Head :
|
||||
// Head asks for a response identical to that of a GET request,
|
||||
// but without the response body.
|
||||
func (r *Fiber) Head(args ...interface{}) {
|
||||
r.register("HEAD", args...)
|
||||
}
|
||||
|
||||
// Patch :
|
||||
// Patch is used to apply partial modifications to a resource.
|
||||
func (r *Fiber) Patch(args ...interface{}) {
|
||||
r.register("PATCH", args...)
|
||||
}
|
||||
|
||||
// Options :
|
||||
// Options is used to describe the communication options
|
||||
// for the target resource.
|
||||
func (r *Fiber) Options(args ...interface{}) {
|
||||
r.register("OPTIONS", args...)
|
||||
}
|
||||
|
||||
// Trace :
|
||||
// Trace performs a message loop-back test
|
||||
// along the path to the target resource.
|
||||
func (r *Fiber) Trace(args ...interface{}) {
|
||||
r.register("TRACE", args...)
|
||||
}
|
||||
|
||||
// Get :
|
||||
// Get requests a representation of the specified resource.
|
||||
// Requests using GET should only retrieve data.
|
||||
func (r *Fiber) Get(args ...interface{}) {
|
||||
r.register("GET", args...)
|
||||
}
|
||||
|
||||
// Use :
|
||||
func (r *Fiber) Use(args ...interface{}) {
|
||||
r.register("*", args...)
|
||||
}
|
||||
|
||||
// All :
|
||||
// All matches any HTTP method
|
||||
func (r *Fiber) All(args ...interface{}) {
|
||||
r.register("*", args...)
|
||||
}
|
||||
|
||||
// Use is another name for All()
|
||||
// People using Expressjs are used to this
|
||||
func (r *Fiber) Use(args ...interface{}) {
|
||||
r.All(args...)
|
||||
}
|
||||
|
||||
// Function to add a route correctly
|
||||
func (r *Fiber) register(method string, args ...interface{}) {
|
||||
// Options
|
||||
var path string
|
||||
|
@ -204,12 +241,15 @@ func (r *Fiber) registerStatic(method, prefix, root string) {
|
|||
if prefix == "" {
|
||||
prefix = "/"
|
||||
}
|
||||
files, _, err := walk(root)
|
||||
files, _, err := walkDir(root)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mount := filepath.Clean(root)
|
||||
for _, file := range files {
|
||||
if strings.Contains(file, ".fasthttp.gz") {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(prefix, strings.Replace(file, mount, "", 1))
|
||||
filePath := file
|
||||
if filepath.Base(filePath) == "index.html" {
|
||||
|
@ -243,7 +283,14 @@ func (r *Fiber) registerHandler(method, path string, handler func(*Ctx)) {
|
|||
r.routes = append(r.routes, &route{method, false, path, regex, params, handler})
|
||||
}
|
||||
|
||||
// handler :
|
||||
// handler create a new context struct from the pool
|
||||
// then try to match a route as efficient as possible.
|
||||
// 1 > loop trough all routes
|
||||
// 2 > if method != * or method != method SKIP
|
||||
// 3 > if any == true or (path == path && params == nil): MATCH
|
||||
// 4 > if regex == nil: SKIP
|
||||
// 5 > if regex.match(path) != true: SKIP
|
||||
// 6 > if params != nil && len(params) > 0 REGEXPARAMS
|
||||
func (r *Fiber) handler(fctx *fasthttp.RequestCtx) {
|
||||
found := false
|
||||
// get custom context from sync pool
|
||||
|
@ -276,8 +323,12 @@ func (r *Fiber) handler(fctx *fasthttp.RequestCtx) {
|
|||
// continue to go to the next route
|
||||
continue
|
||||
}
|
||||
// Skip route if regex does not exist
|
||||
if route.regex == nil {
|
||||
continue
|
||||
}
|
||||
// Skip route if regex does not match
|
||||
if route.regex == nil || !route.regex.MatchString(path) {
|
||||
if !route.regex.MatchString(path) {
|
||||
continue
|
||||
}
|
||||
// If we have parameters, lets find the matches
|
||||
|
@ -299,15 +350,16 @@ func (r *Fiber) handler(fctx *fasthttp.RequestCtx) {
|
|||
// set next to false for next iteration
|
||||
ctx.next = false
|
||||
}
|
||||
// No routes found
|
||||
if !found {
|
||||
// No routes found
|
||||
// Custom 404 handler?
|
||||
ctx.Status(404).Send("Not Found")
|
||||
}
|
||||
// release context back into sync pool
|
||||
releaseCtx(ctx)
|
||||
}
|
||||
|
||||
// Listen :
|
||||
// Listen starts the server with the correct settings
|
||||
func (r *Fiber) Listen(args ...interface{}) {
|
||||
var port string
|
||||
var addr string
|
||||
|
@ -318,52 +370,49 @@ func (r *Fiber) Listen(args ...interface{}) {
|
|||
addr = args[0].(string)
|
||||
port = strconv.Itoa(args[1].(int))
|
||||
}
|
||||
// Disable server header if server name is not given
|
||||
if r.Settings.Name != "" {
|
||||
r.Settings.NoDefaultServerHeader = false
|
||||
}
|
||||
server := &fasthttp.Server{
|
||||
// Fiber custom handler
|
||||
Handler: r.handler,
|
||||
// Server settings
|
||||
Name: r.Settings.Name,
|
||||
Concurrency: r.Settings.Concurrency,
|
||||
DisableKeepalive: r.Settings.DisableKeepAlive,
|
||||
ReadBufferSize: r.Settings.ReadBufferSize,
|
||||
WriteBufferSize: r.Settings.WriteBufferSize,
|
||||
ReadTimeout: r.Settings.ReadTimeout,
|
||||
WriteTimeout: r.Settings.WriteTimeout,
|
||||
IdleTimeout: r.Settings.IdleTimeout,
|
||||
MaxConnsPerIP: r.Settings.MaxConnsPerIP,
|
||||
MaxRequestsPerConn: r.Settings.MaxRequestsPerConn,
|
||||
TCPKeepalive: r.Settings.TCPKeepalive,
|
||||
TCPKeepalivePeriod: r.Settings.TCPKeepalivePeriod,
|
||||
MaxRequestBodySize: r.Settings.MaxRequestBodySize,
|
||||
ReduceMemoryUsage: r.Settings.ReduceMemoryUsage,
|
||||
GetOnly: r.Settings.GetOnly,
|
||||
DisableHeaderNamesNormalizing: r.Settings.DisableHeaderNamesNormalizing,
|
||||
SleepWhenConcurrencyLimitsExceeded: r.Settings.SleepWhenConcurrencyLimitsExceeded,
|
||||
NoDefaultServerHeader: r.Settings.NoDefaultServerHeader,
|
||||
NoDefaultContentType: r.Settings.NoDefaultContentType,
|
||||
KeepHijackedConns: r.Settings.KeepHijackedConns,
|
||||
Handler: r.handler,
|
||||
Name: r.Server,
|
||||
Concurrency: r.Fasthttp.Concurrency,
|
||||
DisableKeepalive: r.Fasthttp.DisableKeepAlive,
|
||||
ReadBufferSize: r.Fasthttp.ReadBufferSize,
|
||||
WriteBufferSize: r.Fasthttp.WriteBufferSize,
|
||||
ReadTimeout: r.Fasthttp.ReadTimeout,
|
||||
WriteTimeout: r.Fasthttp.WriteTimeout,
|
||||
IdleTimeout: r.Fasthttp.IdleTimeout,
|
||||
MaxConnsPerIP: r.Fasthttp.MaxConnsPerIP,
|
||||
MaxRequestsPerConn: r.Fasthttp.MaxRequestsPerConn,
|
||||
TCPKeepalive: r.Fasthttp.TCPKeepalive,
|
||||
TCPKeepalivePeriod: r.Fasthttp.TCPKeepalivePeriod,
|
||||
MaxRequestBodySize: r.Fasthttp.MaxRequestBodySize,
|
||||
ReduceMemoryUsage: r.Fasthttp.ReduceMemoryUsage,
|
||||
GetOnly: r.Fasthttp.GetOnly,
|
||||
DisableHeaderNamesNormalizing: r.Fasthttp.DisableHeaderNamesNormalizing,
|
||||
SleepWhenConcurrencyLimitsExceeded: r.Fasthttp.SleepWhenConcurrencyLimitsExceeded,
|
||||
NoDefaultServerHeader: r.Server == "",
|
||||
NoDefaultContentType: r.Fasthttp.NoDefaultContentType,
|
||||
KeepHijackedConns: r.Fasthttp.KeepHijackedConns,
|
||||
}
|
||||
if r.Settings.ClearTerminal {
|
||||
var cmd *exec.Cmd
|
||||
goos := runtime.GOOS
|
||||
if goos == "windows" {
|
||||
cmd = exec.Command("cmd", "/c", "cls")
|
||||
if r.ClearTerminal {
|
||||
if runtime.GOOS == "linux" {
|
||||
cmd := exec.Command("clear")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Run()
|
||||
} else if runtime.GOOS == "windows" {
|
||||
cmd := exec.Command("cmd", "/c", "cls")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Run()
|
||||
}
|
||||
if goos == "linux" {
|
||||
cmd = exec.Command("clear")
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Run()
|
||||
}
|
||||
if !r.Settings.HideBanner {
|
||||
fmt.Printf(color.HiCyanString(banner), color.GreenString(":"+port), color.HiBlackString("("+Version+")"))
|
||||
if !r.NoBanner {
|
||||
fmt.Printf(banner, cGreen,
|
||||
cBlack+Version,
|
||||
cBlack+"Express on steriods",
|
||||
cGreen+":"+port+cReset,
|
||||
)
|
||||
}
|
||||
if r.Settings.TLSEnable {
|
||||
if err := server.ListenAndServeTLS(fmt.Sprintf("%s:%s", addr, port), r.Settings.CertFile, r.Settings.CertKey); err != nil {
|
||||
if r.CertKey != "" && r.CertFile != "" {
|
||||
if err := server.ListenAndServeTLS(fmt.Sprintf("%s:%s", addr, port), r.CertFile, r.CertKey); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -53,24 +53,24 @@ func getRegex(path string) (*regexp.Regexp, error) {
|
|||
return regex, err
|
||||
}
|
||||
|
||||
func walk(root string) (files []string, dir bool, err error) {
|
||||
// walkDir loops trough directory and store file paths in array
|
||||
func walkDir(root string) (files []string, isDir bool, err error) {
|
||||
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if !info.IsDir() {
|
||||
if !strings.Contains(path, ".fasthttp.gz") {
|
||||
files = append(files, path)
|
||||
}
|
||||
files = append(files, path)
|
||||
} else {
|
||||
dir = true
|
||||
isDir = true
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
})
|
||||
return files, dir, err
|
||||
return files, isDir, err
|
||||
}
|
||||
|
||||
// Credits to @savsgio
|
||||
// https://github.com/savsgio/gotils/blob/master/conv.go
|
||||
|
||||
// b2s converts byte slice to a string without memory allocation.
|
||||
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
|
||||
//
|
||||
// Note it may break if string and/or slice header will change
|
||||
// in the future go versions.
|
||||
func b2s(b []byte) string {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&b))
|
||||
bh := reflect.SliceHeader{
|
||||
|
@ -82,6 +82,9 @@ func b2s(b []byte) string {
|
|||
}
|
||||
|
||||
// s2b converts string to a byte slice without memory allocation.
|
||||
//
|
||||
// Note it may break if string and/or slice header will change
|
||||
// in the future go versions.
|
||||
func s2b(s string) []byte {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
bh := reflect.SliceHeader{
|
||||
|
@ -91,3 +94,32 @@ func s2b(s string) []byte {
|
|||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&bh))
|
||||
}
|
||||
|
||||
// NoCopy embed this type into a struct, which mustn't be copied,
|
||||
// so `go vet` gives a warning if this struct is copied.
|
||||
//
|
||||
// See https://github.com/golang/go/issues/8005#issuecomment-190753527 for details.
|
||||
// and also: https://stackoverflow.com/questions/52494458/nocopy-minimal-example
|
||||
type noCopy struct{}
|
||||
|
||||
// Lock ...
|
||||
func (*noCopy) Lock() {}
|
||||
|
||||
// Unlock ...
|
||||
func (*noCopy) Unlock() {}
|
||||
|
||||
// StringSliceIndexOf returns index position in slice from given string
|
||||
// If value is -1, the string does not found
|
||||
func stringSliceIndexOf(vs []string, s string) int {
|
||||
for i, v := range vs {
|
||||
if v == s {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// StringSliceInclude returns true or false if given string is in slice
|
||||
func stringSliceInclude(vs []string, t string) bool {
|
||||
return stringSliceIndexOf(vs, t) >= 0
|
||||
}
|
Loading…
Reference in New Issue