pull/189/head
Fenny 2020-02-26 19:31:43 -05:00
parent 63353cac7b
commit 2eeb40273c
8 changed files with 287 additions and 413 deletions

122
app.go
View File

@ -23,7 +23,7 @@ import (
) )
// Version of Fiber // Version of Fiber
const Version = "1.7.1" const Version = "1.8.0"
type ( type (
// App denotes the Fiber application. // App denotes the Fiber application.
@ -46,6 +46,8 @@ type (
CaseSensitive bool `default:"false"` CaseSensitive bool `default:"false"`
// Enables the "Server: value" HTTP header. // Enables the "Server: value" HTTP header.
ServerHeader string `default:""` ServerHeader string `default:""`
// Enables handler values to be immutable even if you return from handler
Immutable bool `default:"false"`
// fasthttp settings // fasthttp settings
GETOnly bool `default:"false"` GETOnly bool `default:"false"`
IdleTimeout time.Duration `default:"0"` IdleTimeout time.Duration `default:"0"`
@ -72,19 +74,34 @@ type (
} }
) )
var prefork = flag.Bool("fiber-prefork", false, "use prefork") func init() {
var child = flag.Bool("fiber-child", false, "is child process") flag.Bool("prefork", false, "Use prefork")
flag.Bool("child", false, "Is a child process")
}
// New ... // New : https://fiber.wiki/application#new
func New(settings ...*Settings) (app *App) { func New(settings ...*Settings) (app *App) {
flag.Parse() var prefork bool
var child bool
for _, arg := range os.Args[1:] {
if arg == "-prefork" {
prefork = true
} else if arg == "-child" {
child = true
}
}
app = &App{ app = &App{
child: *child, child: child,
} }
if len(settings) > 0 { if len(settings) > 0 {
opt := settings[0] opt := settings[0]
if !opt.Prefork { if !opt.Prefork {
opt.Prefork = *prefork opt.Prefork = prefork
}
if opt.Immutable {
getString = func(b []byte) string {
return string(b)
}
} }
if opt.Concurrency == 0 { if opt.Concurrency == 0 {
opt.Concurrency = 256 * 1024 opt.Concurrency = 256 * 1024
@ -102,7 +119,7 @@ func New(settings ...*Settings) (app *App) {
return return
} }
app.Settings = &Settings{ app.Settings = &Settings{
Prefork: *prefork, Prefork: prefork,
Concurrency: 256 * 1024, Concurrency: 256 * 1024,
ReadBufferSize: 4096, ReadBufferSize: 4096,
WriteBufferSize: 4096, WriteBufferSize: 4096,
@ -111,89 +128,89 @@ func New(settings ...*Settings) (app *App) {
return return
} }
// Recover // Recover : https://fiber.wiki/application#recover
func (app *App) Recover(cb func(*Ctx)) { func (app *App) Recover(callback func(*Ctx)) {
app.recover = cb app.recover = callback
} }
// Recover // Recover : https://fiber.wiki/application#recover
func (grp *Group) Recover(cb func(*Ctx)) { func (grp *Group) Recover(callback func(*Ctx)) {
grp.app.recover = cb grp.app.recover = callback
} }
// Static ... // Static : https://fiber.wiki/application#static
func (app *App) Static(args ...string) *App { func (app *App) Static(args ...string) *App {
app.registerStatic("/", args...) app.registerStatic("/", args...)
return app return app
} }
// WebSocket ... // WebSocket : https://fiber.wiki/application#websocket
func (app *App) WebSocket(args ...interface{}) *App { func (app *App) WebSocket(args ...interface{}) *App {
app.register("GET", "", args...) app.register(http.MethodGet, "", args...)
return app return app
} }
// Connect ... // Connect : https://fiber.wiki/application#http-methods
func (app *App) Connect(args ...interface{}) *App { func (app *App) Connect(args ...interface{}) *App {
app.register("CONNECT", "", args...) app.register(http.MethodConnect, "", args...)
return app return app
} }
// Put ... // Put : https://fiber.wiki/application#http-methods
func (app *App) Put(args ...interface{}) *App { func (app *App) Put(args ...interface{}) *App {
app.register("PUT", "", args...) app.register(http.MethodPut, "", args...)
return app return app
} }
// Post ... // Post : https://fiber.wiki/application#http-methods
func (app *App) Post(args ...interface{}) *App { func (app *App) Post(args ...interface{}) *App {
app.register("POST", "", args...) app.register(http.MethodPost, "", args...)
return app return app
} }
// Delete ... // Delete : https://fiber.wiki/application#http-methods
func (app *App) Delete(args ...interface{}) *App { func (app *App) Delete(args ...interface{}) *App {
app.register("DELETE", "", args...) app.register(http.MethodDelete, "", args...)
return app return app
} }
// Head ... // Head : https://fiber.wiki/application#http-methods
func (app *App) Head(args ...interface{}) *App { func (app *App) Head(args ...interface{}) *App {
app.register("HEAD", "", args...) app.register(http.MethodHead, "", args...)
return app return app
} }
// Patch ... // Patch : https://fiber.wiki/application#http-methods
func (app *App) Patch(args ...interface{}) *App { func (app *App) Patch(args ...interface{}) *App {
app.register("PATCH", "", args...) app.register(http.MethodPatch, "", args...)
return app return app
} }
// Options ... // Options : https://fiber.wiki/application#http-methods
func (app *App) Options(args ...interface{}) *App { func (app *App) Options(args ...interface{}) *App {
app.register("OPTIONS", "", args...) app.register(http.MethodOptions, "", args...)
return app return app
} }
// Trace ... // Trace : https://fiber.wiki/application#http-methods
func (app *App) Trace(args ...interface{}) *App { func (app *App) Trace(args ...interface{}) *App {
app.register("TRACE", "", args...) app.register(http.MethodOptions, "", args...)
return app return app
} }
// Get ... // Get : https://fiber.wiki/application#http-methods
func (app *App) Get(args ...interface{}) *App { func (app *App) Get(args ...interface{}) *App {
app.register("GET", "", args...) app.register(http.MethodGet, "", args...)
return app return app
} }
// All ... // All : https://fiber.wiki/application#http-methods
func (app *App) All(args ...interface{}) *App { func (app *App) All(args ...interface{}) *App {
app.register("ALL", "", args...) app.register("ALL", "", args...)
return app return app
} }
// Use ... // Use : https://fiber.wiki/application#http-methods
func (app *App) Use(args ...interface{}) *App { func (app *App) Use(args ...interface{}) *App {
app.register("USE", "", args...) app.register("USE", "", args...)
return app return app
@ -214,10 +231,10 @@ func (app *App) Listen(address interface{}, tls ...string) error {
} }
// Create fasthttp server // Create fasthttp server
app.server = app.newServer() app.server = app.newServer()
// Print banner // Print listening message
// if app.Settings.Banner && !app.child { if !app.child {
// fmt.Printf("Fiber-%s is listening on %s\n", Version, addr) fmt.Printf("Fiber v%s listening on %s\n", Version, addr)
// } }
var ln net.Listener var ln net.Listener
var err error var err error
// Prefork enabled // Prefork enabled
@ -238,7 +255,8 @@ func (app *App) Listen(address interface{}, tls ...string) error {
return app.server.Serve(ln) return app.server.Serve(ln)
} }
// Shutdown server gracefully // Shutdown : TODO: Docs
// Shutsdown the server gracefully
func (app *App) Shutdown() error { func (app *App) Shutdown() error {
if app.server == nil { if app.server == nil {
return fmt.Errorf("Server is not running") return fmt.Errorf("Server is not running")
@ -246,11 +264,10 @@ func (app *App) Shutdown() error {
return app.server.Shutdown() return app.server.Shutdown()
} }
// Test takes a http.Request and execute a fake connection to the application // Test : https://fiber.wiki/application#test
// It returns a http.Response when the connection was successful func (app *App) Test(request *http.Request) (*http.Response, error) {
func (app *App) Test(req *http.Request) (*http.Response, error) {
// Get raw http request // Get raw http request
reqRaw, err := httputil.DumpRequest(req, true) reqRaw, err := httputil.DumpRequest(request, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -287,7 +304,7 @@ func (app *App) Test(req *http.Request) (*http.Response, error) {
reader := strings.NewReader(getString(respRaw)) reader := strings.NewReader(getString(respRaw))
buffer := bufio.NewReader(reader) buffer := bufio.NewReader(reader)
// Convert raw HTTP response to http.Response // Convert raw HTTP response to http.Response
resp, err := http.ReadResponse(buffer, req) resp, err := http.ReadResponse(buffer, request)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -299,11 +316,11 @@ func (app *App) Test(req *http.Request) (*http.Response, error) {
func (app *App) prefork(address string) (ln net.Listener, err error) { func (app *App) prefork(address string) (ln net.Listener, err error) {
// Master proc // Master proc
if !app.child { if !app.child {
addr, err := net.ResolveTCPAddr("tcp", address) addr, err := net.ResolveTCPAddr("tcp4", address)
if err != nil { if err != nil {
return ln, err return ln, err
} }
tcplistener, err := net.ListenTCP("tcp", addr) tcplistener, err := net.ListenTCP("tcp4", addr)
if err != nil { if err != nil {
return ln, err return ln, err
} }
@ -311,14 +328,14 @@ func (app *App) prefork(address string) (ln net.Listener, err error) {
if err != nil { if err != nil {
return ln, err return ln, err
} }
files := []*os.File{fl}
childs := make([]*exec.Cmd, runtime.NumCPU()/2) childs := make([]*exec.Cmd, runtime.NumCPU()/2)
// #nosec G204 // #nosec G204
for i := range childs { for i := range childs {
childs[i] = exec.Command(os.Args[0], "-fiber-prefork", "-fiber-child") childs[i] = exec.Command(os.Args[0], append(os.Args[1:], "-prefork", "-child")...)
childs[i].Stdout = os.Stdout childs[i].Stdout = os.Stdout
childs[i].Stderr = os.Stderr childs[i].Stderr = os.Stderr
childs[i].ExtraFiles = []*os.File{fl} childs[i].ExtraFiles = files
if err := childs[i].Start(); err != nil { if err := childs[i].Start(); err != nil {
return ln, err return ln, err
} }
@ -331,6 +348,7 @@ func (app *App) prefork(address string) (ln net.Listener, err error) {
} }
os.Exit(0) os.Exit(0)
} else { } else {
runtime.GOMAXPROCS(1)
ln, err = net.FileListener(os.NewFile(3, "")) ln, err = net.FileListener(os.NewFile(3, ""))
} }
return ln, err return ln, err

View File

@ -5,10 +5,8 @@
package fiber package fiber
import ( import (
"bytes"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"html/template"
"io/ioutil" "io/ioutil"
"log" "log"
"mime" "mime"
@ -19,14 +17,8 @@ import (
"sync" "sync"
"time" "time"
// templates
pug "github.com/Joker/jade"
handlebars "github.com/aymerick/raymond"
mustache "github.com/cbroglie/mustache"
amber "github.com/eknkc/amber"
// core
websocket "github.com/fasthttp/websocket" websocket "github.com/fasthttp/websocket"
template "github.com/gofiber/template"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
fasthttp "github.com/valyala/fasthttp" fasthttp "github.com/valyala/fasthttp"
) )
@ -42,7 +34,6 @@ type Ctx struct {
params *[]string params *[]string
values []string values []string
Fasthttp *fasthttp.RequestCtx Fasthttp *fasthttp.RequestCtx
Socket *websocket.Conn
} }
// Ctx pool // Ctx pool
@ -67,7 +58,6 @@ func releaseCtx(ctx *Ctx) {
ctx.params = nil ctx.params = nil
ctx.values = nil ctx.values = nil
ctx.Fasthttp = nil ctx.Fasthttp = nil
ctx.Socket = nil
poolCtx.Put(ctx) poolCtx.Put(ctx)
} }
@ -115,18 +105,17 @@ func releaseConn(conn *Conn) {
// Cookie : struct // Cookie : struct
type Cookie struct { type Cookie struct {
Expire int // time.Unix(1578981376, 0) Name string
MaxAge int Value string
Domain string Path string
Path string Domain string
Expires time.Time
HTTPOnly bool
Secure bool Secure bool
SameSite string HTTPOnly bool
} }
// Accepts : https://fiber.wiki/context#accepts // Accepts : https://fiber.wiki/context#accepts
func (ctx *Ctx) Accepts(offers ...string) string { func (ctx *Ctx) Accepts(offers ...string) (offer string) {
if len(offers) == 0 { if len(offers) == 0 {
return "" return ""
} }
@ -136,8 +125,8 @@ func (ctx *Ctx) Accepts(offers ...string) string {
} }
specs := strings.Split(h, ",") specs := strings.Split(h, ",")
for _, offer := range offers { for _, value := range offers {
mimetype := getType(offer) mimetype := getType(value)
// if mimetype != "" { // if mimetype != "" {
// mimetype = strings.Split(mimetype, ";")[0] // mimetype = strings.Split(mimetype, ";")[0]
// } else { // } else {
@ -146,16 +135,16 @@ func (ctx *Ctx) Accepts(offers ...string) string {
for _, spec := range specs { for _, spec := range specs {
spec = strings.TrimSpace(spec) spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*/*") { if strings.HasPrefix(spec, "*/*") {
return offer return value
} }
if strings.HasPrefix(spec, mimetype) { if strings.HasPrefix(spec, mimetype) {
return offer return value
} }
if strings.Contains(spec, "/*") { if strings.Contains(spec, "/*") {
if strings.HasPrefix(spec, strings.Split(mimetype, "/")[0]) { if strings.HasPrefix(spec, strings.Split(mimetype, "/")[0]) {
return offer return value
} }
} }
} }
@ -164,7 +153,7 @@ func (ctx *Ctx) Accepts(offers ...string) string {
} }
// AcceptsCharsets : https://fiber.wiki/context#acceptscharsets // AcceptsCharsets : https://fiber.wiki/context#acceptscharsets
func (ctx *Ctx) AcceptsCharsets(offers ...string) string { func (ctx *Ctx) AcceptsCharsets(offers ...string) (offer string) {
if len(offers) == 0 { if len(offers) == 0 {
return "" return ""
} }
@ -175,14 +164,14 @@ func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
} }
specs := strings.Split(h, ",") specs := strings.Split(h, ",")
for _, offer := range offers { for _, value := range offers {
for _, spec := range specs { for _, spec := range specs {
spec = strings.TrimSpace(spec) spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*") { if strings.HasPrefix(spec, "*") {
return offer return value
} }
if strings.HasPrefix(spec, offer) { if strings.HasPrefix(spec, value) {
return offer return value
} }
} }
} }
@ -190,7 +179,7 @@ func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
} }
// AcceptsEncodings : https://fiber.wiki/context#acceptsencodings // AcceptsEncodings : https://fiber.wiki/context#acceptsencodings
func (ctx *Ctx) AcceptsEncodings(offers ...string) string { func (ctx *Ctx) AcceptsEncodings(offers ...string) (offer string) {
if len(offers) == 0 { if len(offers) == 0 {
return "" return ""
} }
@ -201,14 +190,14 @@ func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
} }
specs := strings.Split(h, ",") specs := strings.Split(h, ",")
for _, offer := range offers { for _, value := range offers {
for _, spec := range specs { for _, spec := range specs {
spec = strings.TrimSpace(spec) spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*") { if strings.HasPrefix(spec, "*") {
return offer return value
} }
if strings.HasPrefix(spec, offer) { if strings.HasPrefix(spec, value) {
return offer return value
} }
} }
} }
@ -216,7 +205,7 @@ func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
} }
// AcceptsLanguages : https://fiber.wiki/context#acceptslanguages // AcceptsLanguages : https://fiber.wiki/context#acceptslanguages
func (ctx *Ctx) AcceptsLanguages(offers ...string) string { func (ctx *Ctx) AcceptsLanguages(offers ...string) (offer string) {
if len(offers) == 0 { if len(offers) == 0 {
return "" return ""
} }
@ -226,14 +215,14 @@ func (ctx *Ctx) AcceptsLanguages(offers ...string) string {
} }
specs := strings.Split(h, ",") specs := strings.Split(h, ",")
for _, offer := range offers { for _, value := range offers {
for _, spec := range specs { for _, spec := range specs {
spec = strings.TrimSpace(spec) spec = strings.TrimSpace(spec)
if strings.HasPrefix(spec, "*") { if strings.HasPrefix(spec, "*") {
return offer return value
} }
if strings.HasPrefix(spec, offer) { if strings.HasPrefix(spec, value) {
return offer return value
} }
} }
} }
@ -273,38 +262,29 @@ func (ctx *Ctx) BaseURL() string {
} }
// Body : https://fiber.wiki/context#body // Body : https://fiber.wiki/context#body
func (ctx *Ctx) Body(args ...interface{}) string { func (ctx *Ctx) Body(key ...string) string {
if len(args) == 0 { // Return request body
if len(key) == 0 {
return getString(ctx.Fasthttp.Request.Body()) return getString(ctx.Fasthttp.Request.Body())
} }
// Return post value by key
if len(args) == 1 { if len(key) > 0 {
switch arg := args[0].(type) { return getString(ctx.Fasthttp.Request.PostArgs().Peek(key[0]))
case string:
return getString(ctx.Fasthttp.Request.PostArgs().Peek(arg))
case []byte:
return getString(ctx.Fasthttp.Request.PostArgs().PeekBytes(arg))
case func(string, string):
ctx.Fasthttp.Request.PostArgs().VisitAll(func(k []byte, v []byte) {
arg(getString(k), getString(v))
})
default:
return getString(ctx.Fasthttp.Request.Body())
}
} }
return "" return ""
} }
// BodyParser : https://fiber.wiki/context#bodyparser // BodyParser : https://fiber.wiki/context#bodyparser
func (ctx *Ctx) BodyParser(v interface{}) error { func (ctx *Ctx) BodyParser(out interface{}) error {
// TODO : Query Params
ctype := getString(ctx.Fasthttp.Request.Header.ContentType()) ctype := getString(ctx.Fasthttp.Request.Header.ContentType())
// application/json // application/json
if strings.HasPrefix(ctype, MIMEApplicationJSON) { if strings.HasPrefix(ctype, MIMEApplicationJSON) {
return jsoniter.Unmarshal(ctx.Fasthttp.Request.Body(), v) return jsoniter.Unmarshal(ctx.Fasthttp.Request.Body(), out)
} }
// application/xml text/xml // application/xml text/xml
if strings.HasPrefix(ctype, MIMEApplicationXML) || strings.HasPrefix(ctype, MIMETextXML) { if strings.HasPrefix(ctype, MIMEApplicationXML) || strings.HasPrefix(ctype, MIMETextXML) {
return xml.Unmarshal(ctx.Fasthttp.Request.Body(), v) return xml.Unmarshal(ctx.Fasthttp.Request.Body(), out)
} }
// application/x-www-form-urlencoded // application/x-www-form-urlencoded
if strings.HasPrefix(ctype, MIMEApplicationForm) { if strings.HasPrefix(ctype, MIMEApplicationForm) {
@ -312,7 +292,7 @@ func (ctx *Ctx) BodyParser(v interface{}) error {
if err != nil { if err != nil {
return err return err
} }
return schemaDecoder.Decode(v, data) return schemaDecoder.Decode(out, data)
} }
// multipart/form-data // multipart/form-data
if strings.HasPrefix(ctype, MIMEMultipartForm) { if strings.HasPrefix(ctype, MIMEMultipartForm) {
@ -320,18 +300,18 @@ func (ctx *Ctx) BodyParser(v interface{}) error {
if err != nil { if err != nil {
return err return err
} }
return schemaDecoder.Decode(v, data.Value) return schemaDecoder.Decode(out, data.Value)
} }
return fmt.Errorf("cannot parse content-type: %v", ctype) return fmt.Errorf("BodyParser: cannot parse content-type: %v", ctype)
} }
// ClearCookie : https://fiber.wiki/context#clearcookie // ClearCookie : https://fiber.wiki/context#clearcookie
func (ctx *Ctx) ClearCookie(name ...string) { func (ctx *Ctx) ClearCookie(key ...string) {
if len(name) > 0 { if len(key) > 0 {
for i := range name { for i := range key {
//ctx.Fasthttp.Request.Header.DelAllCookies() //ctx.Fasthttp.Request.Header.DelAllCookies()
ctx.Fasthttp.Response.Header.DelClientCookie(name[i]) ctx.Fasthttp.Response.Header.DelClientCookie(key[i])
} }
return return
} }
@ -342,75 +322,24 @@ func (ctx *Ctx) ClearCookie(name ...string) {
} }
// Cookie : https://fiber.wiki/context#cookie // Cookie : https://fiber.wiki/context#cookie
func (ctx *Ctx) Cookie(key, value string, options ...interface{}) { func (ctx *Ctx) Cookie(cookie *Cookie) {
cook := &fasthttp.Cookie{} fcookie := &fasthttp.Cookie{}
fcookie.SetKey(cookie.Name)
cook.SetKey(key) fcookie.SetValue(cookie.Value)
cook.SetValue(value) fcookie.SetPath(cookie.Path)
fcookie.SetDomain(cookie.Domain)
if len(options) > 0 { fcookie.SetExpire(cookie.Expires)
switch opt := options[0].(type) { fcookie.SetSecure(cookie.Secure)
case *Cookie: fcookie.SetHTTPOnly(cookie.HTTPOnly)
if opt.Expire > 0 { ctx.Fasthttp.Response.Header.SetCookie(fcookie)
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)
} }
// Cookies : https://fiber.wiki/context#cookies // Cookies : https://fiber.wiki/context#cookies
func (ctx *Ctx) Cookies(args ...interface{}) string { func (ctx *Ctx) Cookies(key ...string) (value string) {
if len(args) == 0 { if len(key) == 0 {
return ctx.Get(fasthttp.HeaderCookie) return ctx.Get(fasthttp.HeaderCookie)
} }
return getString(ctx.Fasthttp.Request.Header.Cookie(key[0]))
switch arg := args[0].(type) {
case string:
return getString(ctx.Fasthttp.Request.Header.Cookie(arg))
case []byte:
return getString(ctx.Fasthttp.Request.Header.CookieBytes(arg))
case func(string, string):
ctx.Fasthttp.Request.Header.VisitAllCookie(func(k, v []byte) {
arg(getString(k), getString(v))
})
default:
return ctx.Get(fasthttp.HeaderCookie)
}
return ""
} }
// Download : https://fiber.wiki/context#download // Download : https://fiber.wiki/context#download
@ -431,30 +360,27 @@ func (ctx *Ctx) Error() error {
} }
// Format : https://fiber.wiki/context#format // Format : https://fiber.wiki/context#format
func (ctx *Ctx) Format(args ...interface{}) { func (ctx *Ctx) Format(body interface{}) {
var body string var b string
accept := ctx.Accepts("html", "json") accept := ctx.Accepts("html", "json")
for i := range args { switch val := body.(type) {
switch arg := args[i].(type) { case string:
case string: b = val
body = arg case []byte:
case []byte: b = getString(val)
body = getString(arg) default:
default: b = fmt.Sprintf("%v", val)
body = fmt.Sprintf("%v", arg) }
} switch accept {
switch accept { case "html":
case "html": ctx.SendString("<p>" + b + "</p>")
ctx.SendString("<p>" + body + "</p>") case "json":
case "json": if err := ctx.JSON(body); err != nil {
if err := ctx.JSON(body); err != nil { log.Println("Format: error serializing json ", err)
log.Println("Format: error serializing json ", err)
}
default:
ctx.SendString(body)
} }
default:
ctx.SendString(b)
} }
} }
@ -464,7 +390,7 @@ func (ctx *Ctx) FormFile(key string) (*multipart.FileHeader, error) {
} }
// FormValue : https://fiber.wiki/context#formvalue // FormValue : https://fiber.wiki/context#formvalue
func (ctx *Ctx) FormValue(key string) string { func (ctx *Ctx) FormValue(key string) (value string) {
return getString(ctx.Fasthttp.FormValue(key)) return getString(ctx.Fasthttp.FormValue(key))
} }
@ -474,7 +400,7 @@ func (ctx *Ctx) Fresh() bool {
} }
// Get : https://fiber.wiki/context#get // Get : https://fiber.wiki/context#get
func (ctx *Ctx) Get(key string) string { func (ctx *Ctx) Get(key string) (value string) {
if key == "referrer" { if key == "referrer" {
key = "referer" key = "referer"
} }
@ -501,26 +427,26 @@ func (ctx *Ctx) IPs() []string {
} }
// Is : https://fiber.wiki/context#is // Is : https://fiber.wiki/context#is
func (ctx *Ctx) Is(ext string) bool { func (ctx *Ctx) Is(extension string) (match bool) {
if ext[0] != '.' { if extension[0] != '.' {
ext = "." + ext extension = "." + extension
} }
exts, _ := mime.ExtensionsByType(ctx.Get(fasthttp.HeaderContentType)) exts, _ := mime.ExtensionsByType(ctx.Get(fasthttp.HeaderContentType))
if len(exts) > 0 { if len(exts) > 0 {
for _, item := range exts { for _, item := range exts {
if item == ext { if item == extension {
return true return true
} }
} }
} }
return false return
} }
// JSON : https://fiber.wiki/context#json // JSON : https://fiber.wiki/context#json
func (ctx *Ctx) JSON(v interface{}) error { func (ctx *Ctx) JSON(json interface{}) error {
ctx.Fasthttp.Response.Header.SetContentType(MIMEApplicationJSON) ctx.Fasthttp.Response.Header.SetContentType(MIMEApplicationJSON)
raw, err := jsoniter.Marshal(&v) raw, err := jsoniter.Marshal(&json)
if err != nil { if err != nil {
ctx.Fasthttp.Response.SetBodyString("") ctx.Fasthttp.Response.SetBodyString("")
return err return err
@ -531,15 +457,15 @@ func (ctx *Ctx) JSON(v interface{}) error {
} }
// JSONP : https://fiber.wiki/context#jsonp // JSONP : https://fiber.wiki/context#jsonp
func (ctx *Ctx) JSONP(v interface{}, cb ...string) error { func (ctx *Ctx) JSONP(json interface{}, callback ...string) error {
raw, err := jsoniter.Marshal(&v) raw, err := jsoniter.Marshal(&json)
if err != nil { if err != nil {
return err return err
} }
str := "callback(" str := "callback("
if len(cb) > 0 { if len(callback) > 0 {
str = cb[0] + "(" str = callback[0] + "("
} }
str += getString(raw) + ");" str += getString(raw) + ");"
@ -568,12 +494,12 @@ func (ctx *Ctx) Links(link ...string) {
} }
// Locals : https://fiber.wiki/context#locals // Locals : https://fiber.wiki/context#locals
func (ctx *Ctx) Locals(key string, val ...interface{}) interface{} { func (ctx *Ctx) Locals(key string, value ...interface{}) (val interface{}) {
if len(val) == 0 { if len(value) == 0 {
return ctx.Fasthttp.UserValue(key) return ctx.Fasthttp.UserValue(key)
} }
ctx.Fasthttp.SetUserValue(key, val[0]) ctx.Fasthttp.SetUserValue(key, value[0])
return nil return value[0]
} }
// Location : https://fiber.wiki/context#location // Location : https://fiber.wiki/context#location
@ -608,16 +534,16 @@ func (ctx *Ctx) OriginalURL() string {
} }
// Params : https://fiber.wiki/context#params // Params : https://fiber.wiki/context#params
func (ctx *Ctx) Params(key string) string { func (ctx *Ctx) Params(key string) (value string) {
if ctx.params == nil { if ctx.params == nil {
return "" return
} }
for i := 0; i < len(*ctx.params); i++ { for i := 0; i < len(*ctx.params); i++ {
if (*ctx.params)[i] == key { if (*ctx.params)[i] == key {
return ctx.values[i] return ctx.values[i]
} }
} }
return "" return
} }
// Path : https://fiber.wiki/context#path // Path : https://fiber.wiki/context#path
@ -634,7 +560,7 @@ func (ctx *Ctx) Protocol() string {
} }
// Query : https://fiber.wiki/context#query // Query : https://fiber.wiki/context#query
func (ctx *Ctx) Query(key string) string { func (ctx *Ctx) Query(key string) (value string) {
return getString(ctx.Fasthttp.QueryArgs().Peek(key)) return getString(ctx.Fasthttp.QueryArgs().Peek(key))
} }
@ -642,7 +568,7 @@ func (ctx *Ctx) Query(key string) string {
func (ctx *Ctx) Range() { func (ctx *Ctx) Range() {
// https://expressjs.com/en/api.html#req.range // https://expressjs.com/en/api.html#req.range
// https://github.com/jshttp/range-parser/blob/master/index.js // https://github.com/jshttp/range-parser/blob/master/index.js
// r := ctx.Fasthttp.Request.Header.Peek(fasthttp.HeaderRange) // r := ctx.Fasthttp.Request.Header.Peek(HeaderRange)
// *magic* // *magic*
} }
@ -658,18 +584,18 @@ func (ctx *Ctx) Redirect(path string, status ...int) {
} }
// Render : https://fiber.wiki/context#render // Render : https://fiber.wiki/context#render
func (ctx *Ctx) Render(file string, data interface{}, e ...string) error { func (ctx *Ctx) Render(file string, bind interface{}, engine ...string) error {
var err error var err error
var raw []byte var raw []byte
var html string var html string
var engine string var e string
if len(e) > 0 { if len(engine) > 0 {
engine = e[0] e = engine[0]
} else if ctx.app.Settings.ViewEngine != "" { } else if ctx.app.Settings.ViewEngine != "" {
engine = ctx.app.Settings.ViewEngine e = ctx.app.Settings.ViewEngine
} else { } else {
engine = filepath.Ext(file)[1:] e = filepath.Ext(file)[1:]
} }
if ctx.app.Settings.ViewFolder != "" { if ctx.app.Settings.ViewFolder != "" {
file = filepath.Join(ctx.app.Settings.ViewFolder, file) file = filepath.Join(ctx.app.Settings.ViewFolder, file)
@ -681,53 +607,27 @@ func (ctx *Ctx) Render(file string, data interface{}, e ...string) error {
return err return err
} }
switch engine { switch e {
case "amber": // https://github.com/eknkc/amber case "amber": // https://github.com/eknkc/amber
var buf bytes.Buffer if html, err = template.Amber(getString(raw), bind); err != nil {
var tmpl *template.Template
if tmpl, err = amber.Compile(getString(raw), amber.DefaultOptions); err != nil {
return err return err
} }
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
case "handlebars": // https://github.com/aymerick/raymond case "handlebars": // https://github.com/aymerick/raymond
if html, err = handlebars.Render(getString(raw), data); err != nil { if html, err = template.Handlebars(getString(raw), bind); err != nil {
return err return err
} }
case "mustache": // https://github.com/cbroglie/mustache case "mustache": // https://github.com/cbroglie/mustache
if html, err = mustache.Render(getString(raw), data); err != nil { if html, err = template.Mustache(getString(raw), bind); err != nil {
return err return err
} }
case "pug": // https://github.com/Joker/jade case "pug": // https://github.com/Joker/jade
var parsed string if html, err = template.Pug(getString(raw), bind); err != nil {
var buf bytes.Buffer
var tmpl *template.Template
if parsed, err = pug.Parse("", raw); err != nil {
return err return err
} }
if tmpl, err = template.New("").Parse(parsed); err != nil {
return err
}
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
default: // https://golang.org/pkg/text/template/ default: // https://golang.org/pkg/text/template/
var buf bytes.Buffer if html, err = template.HTML(getString(raw), bind); err != nil {
var tmpl *template.Template
if tmpl, err = template.New("").Parse(getString(raw)); err != nil {
return err return err
} }
if err = tmpl.Execute(&buf, data); err != nil {
return err
}
html = buf.String()
} }
ctx.Set("Content-Type", "text/html") ctx.Set("Content-Type", "text/html")
ctx.SendString(html) ctx.SendString(html)
@ -740,8 +640,8 @@ func (ctx *Ctx) Route() *Route {
} }
// SaveFile : https://fiber.wiki/context#secure // SaveFile : https://fiber.wiki/context#secure
func (ctx *Ctx) SaveFile(fh *multipart.FileHeader, path string) error { func (ctx *Ctx) SaveFile(fileheader *multipart.FileHeader, path string) error {
return fasthttp.SaveMultipartFile(fh, path) return fasthttp.SaveMultipartFile(fileheader, path)
} }
// Secure : https://fiber.wiki/context#secure // Secure : https://fiber.wiki/context#secure
@ -750,18 +650,19 @@ func (ctx *Ctx) Secure() bool {
} }
// Send : https://fiber.wiki/context#send // Send : https://fiber.wiki/context#send
func (ctx *Ctx) Send(args ...interface{}) { func (ctx *Ctx) Send(bodies ...interface{}) {
if len(args) == 0 { // if len(bodies) > 0 {
return // ctx.Fasthttp.Response.SetBodyString("")
} // }
for i := range bodies {
switch body := args[0].(type) { switch body := bodies[i].(type) {
case string: case string:
ctx.Fasthttp.Response.SetBodyString(body) ctx.Fasthttp.Response.AppendBodyString(body)
case []byte: case []byte:
ctx.Fasthttp.Response.SetBodyString(getString(body)) ctx.Fasthttp.Response.AppendBodyString(getString(body))
default: default:
ctx.Fasthttp.Response.SetBodyString(fmt.Sprintf("%v", body)) ctx.Fasthttp.Response.AppendBodyString(fmt.Sprintf("%v", body))
}
} }
} }
@ -803,19 +704,14 @@ func (ctx *Ctx) Set(key string, val string) {
} }
// Subdomains : https://fiber.wiki/context#subdomains // Subdomains : https://fiber.wiki/context#subdomains
func (ctx *Ctx) Subdomains(offset ...int) (subs []string) { func (ctx *Ctx) Subdomains(offset ...int) []string {
o := 2 o := 2
if len(offset) > 0 { if len(offset) > 0 {
o = offset[0] o = offset[0]
} }
subs = strings.Split(ctx.Hostname(), ".") subdomains := strings.Split(ctx.Hostname(), ".")
subs = subs[:len(subs)-o] subdomains = subdomains[:len(subdomains)-o]
return subs return subdomains
}
// SignedCookies : https://fiber.wiki/context#signedcookies
func (ctx *Ctx) SignedCookies() {
} }
// Stale : https://fiber.wiki/context#stale // Stale : https://fiber.wiki/context#stale
@ -854,9 +750,9 @@ func (ctx *Ctx) Vary(fields ...string) {
} }
// Write : https://fiber.wiki/context#write // Write : https://fiber.wiki/context#write
func (ctx *Ctx) Write(args ...interface{}) { func (ctx *Ctx) Write(bodies ...interface{}) {
for i := range args { for i := range bodies {
switch body := args[i].(type) { switch body := bodies[i].(type) {
case string: case string:
ctx.Fasthttp.Response.AppendBodyString(body) ctx.Fasthttp.Response.AppendBodyString(body)
case []byte: case []byte:

View File

@ -15,6 +15,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"time"
) )
func Test_Accepts(t *testing.T) { func Test_Accepts(t *testing.T) {
@ -129,7 +130,6 @@ func Test_BaseURL(t *testing.T) {
func Test_Body(t *testing.T) { func Test_Body(t *testing.T) {
app := New() app := New()
app.Post("/test", func(c *Ctx) { app.Post("/test", func(c *Ctx) {
c.Body(1)
expect := "john=doe" expect := "john=doe"
result := c.Body() result := c.Body()
if result != expect { if result != expect {
@ -140,21 +140,6 @@ func Test_Body(t *testing.T) {
if result != expect { if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result) t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
} }
expect = "doe"
result = c.Body([]byte("john"))
if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
c.Body(func(k, v string) {
expect = "john"
if k != "john" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, k)
}
expect = "doe"
if v != "doe" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, v)
}
})
}) })
data := url.Values{} data := url.Values{}
data.Set("john", "doe") data.Set("john", "doe")
@ -196,7 +181,6 @@ func Test_BodyParser(t *testing.T) {
func Test_Cookies(t *testing.T) { func Test_Cookies(t *testing.T) {
app := New() app := New()
app.Get("/test", func(c *Ctx) { app.Get("/test", func(c *Ctx) {
c.Cookies(1)
expect := "john=doe" expect := "john=doe"
result := c.Cookies() result := c.Cookies()
if result != expect { if result != expect {
@ -207,21 +191,6 @@ func Test_Cookies(t *testing.T) {
if result != expect { if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result) t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
} }
expect = "doe"
result = c.Cookies([]byte("john"))
if result != expect {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
c.Cookies(func(k, v string) {
expect = "john"
if k != "john" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, k)
}
expect = "doe"
if v != "doe" {
t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, v)
}
})
}) })
req, _ := http.NewRequest("GET", "/test", nil) req, _ := http.NewRequest("GET", "/test", nil)
@ -621,20 +590,6 @@ func Test_Secure(t *testing.T) {
t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode) t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
} }
} }
func Test_SignedCookies(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
c.SignedCookies()
})
req, _ := http.NewRequest("GET", "/test", nil)
resp, err := app.Test(req)
if err != nil {
t.Fatalf(`%s: %s`, t.Name(), err)
}
if resp.StatusCode != 200 {
t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_Stale(t *testing.T) { func Test_Stale(t *testing.T) {
app := New() app := New()
app.Get("/test", func(c *Ctx) { app.Get("/test", func(c *Ctx) {
@ -758,16 +713,16 @@ func Test_ClearCookie(t *testing.T) {
} }
func Test_Cookie(t *testing.T) { func Test_Cookie(t *testing.T) {
app := New() app := New()
expire := time.Now().Add(24 * time.Hour)
var dst []byte
dst = expire.In(time.UTC).AppendFormat(dst, time.RFC1123)
httpdate := strings.Replace(string(dst), "UTC", "GMT", -1)
app.Get("/test", func(c *Ctx) { app.Get("/test", func(c *Ctx) {
options := &Cookie{ cookie := new(Cookie)
MaxAge: 60, cookie.Name = "username"
Domain: "example.com", cookie.Value = "jon"
Path: "/", cookie.Expires = expire
HTTPOnly: true, c.Cookie(cookie)
Secure: false,
SameSite: "lax",
}
c.Cookie("name", "john", options)
}) })
req, _ := http.NewRequest("GET", "http://example.com/test", nil) req, _ := http.NewRequest("GET", "http://example.com/test", nil)
resp, err := app.Test(req) resp, err := app.Test(req)
@ -777,8 +732,8 @@ func Test_Cookie(t *testing.T) {
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode) t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
} }
if !strings.Contains(resp.Header.Get("Set-Cookie"), "name=john; max-age=60; domain=example.com; path=/; HttpOnly; SameSite=Lax") { if !strings.Contains(resp.Header.Get("Set-Cookie"), "username=jon; expires="+string(httpdate)+"; path=/") {
t.Fatalf(`%s: Expecting %s`, t.Name(), "name=john; max-age=60; domain=example.com; path=/; HttpOnly; SameSite=Lax") t.Fatalf(`%s: Expecting %s`, t.Name(), "username=jon; expires="+string(httpdate)+"; path=/")
} }
} }
func Test_Download(t *testing.T) { func Test_Download(t *testing.T) {

3
go.mod
View File

@ -3,8 +3,9 @@ module github.com/gofiber/fiber
go 1.11 go 1.11
require ( require (
github.com/fasthttp/websocket v1.4.1
github.com/gorilla/schema v1.1.0 github.com/gorilla/schema v1.1.0
github.com/gofiber/template v1.0.0
github.com/json-iterator/go v1.1.9 github.com/json-iterator/go v1.1.9
github.com/valyala/fasthttp v1.9.0 github.com/valyala/fasthttp v1.9.0
github.com/fasthttp/websocket v1.4.2
) )

15
go.sum
View File

@ -1,7 +1,6 @@
github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE= github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE=
github.com/Joker/jade v1.0.0 h1:lOCEPvTAtWfLpSZYMOv/g44MGQFAolbKh2khHHGu0Kc= github.com/Joker/jade v1.0.0 h1:lOCEPvTAtWfLpSZYMOv/g44MGQFAolbKh2khHHGu0Kc=
github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8= github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8=
github.com/aymerick/raymond v1.1.0 h1:phuNN2s67eI/HtO8CrvqFcdR2JP+BtkGJZ9n692Hr2Y=
github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0= github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0=
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/cbroglie/mustache v1.0.1 h1:ivMg8MguXq/rrz2eu3tw6g3b16+PQhoTn6EZAhst2mw= github.com/cbroglie/mustache v1.0.1 h1:ivMg8MguXq/rrz2eu3tw6g3b16+PQhoTn6EZAhst2mw=
@ -10,17 +9,17 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/fasthttp/websocket v1.4.1 h1:fisgNMCNCbIPM5GRRRTAckRrynbSzf76fevcJYJYnSM= github.com/fasthttp/websocket v1.4.2 h1:AU/zSiIIAuJjBMf5o+vO0syGOnEfvZRu40xIhW/3RuM=
github.com/fasthttp/websocket v1.4.1/go.mod h1:toetUvZ3KISxtZERe0wzPPpnaN8GZCKHCowWctwA50o= github.com/fasthttp/websocket v1.4.2/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
github.com/gofiber/template v1.0.0 h1:Vf4Fby9zUWVQyY2y69KKyRHsEYlIE+Pxb25M+jiaEL0=
github.com/gofiber/template v1.0.0/go.mod h1:+bij+R0NI6urTg2jtQvPj5wb2uWMxW9eYGsAN3QhnP0=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY= github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 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/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs= github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= 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/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 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
@ -28,18 +27,16 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 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/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274 h1:F52t1X2ziOrMcQMVHo8ZxwOrDTMAq6MrlKtL1Atu2wU= github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY=
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274/go.mod h1:w803/Fg1m0hrp1ZT9KNfQe4E4+WOMMFLcgzPvOcye10= github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/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 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.4.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
github.com/valyala/fasthttp v1.9.0 h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw= github.com/valyala/fasthttp v1.9.0 h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw=
github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= 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/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -4,7 +4,10 @@
package fiber package fiber
import "strings" import (
"net/http"
"strings"
)
// Group ... // Group ...
type Group struct { type Group struct {
@ -12,10 +15,10 @@ type Group struct {
app *App app *App
} }
// Group ... // Group : https://fiber.wiki/application#group
func (app *App) Group(prefix string, args ...interface{}) *Group { func (app *App) Group(prefix string, handlers ...interface{}) *Group {
if len(args) > 0 { if len(handlers) > 0 {
app.register("USE", prefix, args...) app.register("USE", prefix, handlers...)
} }
return &Group{ return &Group{
prefix: prefix, prefix: prefix,
@ -23,102 +26,102 @@ func (app *App) Group(prefix string, args ...interface{}) *Group {
} }
} }
// Group ... // Group : https://fiber.wiki/application#group
func (grp *Group) Group(newPrfx string, args ...interface{}) *Group { func (grp *Group) Group(prefix string, handlers ...interface{}) *Group {
var prefix = grp.prefix var oldPrefix = grp.prefix
if len(newPrfx) > 0 && newPrfx[0] != '/' && newPrfx[0] != '*' { if len(prefix) > 0 && prefix[0] != '/' && prefix[0] != '*' {
newPrfx = "/" + newPrfx prefix = "/" + prefix
} }
// When grouping, always remove single slash // When grouping, always remove single slash
if len(prefix) > 0 && newPrfx == "/" { if len(oldPrefix) > 0 && prefix == "/" {
newPrfx = "" prefix = ""
} }
// Prepent group prefix if exist // Prepent group prefix if exist
prefix = prefix + newPrfx newPrefix := oldPrefix + prefix
// Clean path by removing double "//" => "/" // Clean path by removing double "//" => "/"
prefix = strings.Replace(prefix, "//", "/", -1) newPrefix = strings.Replace(newPrefix, "//", "/", -1)
if len(args) > 0 { if len(handlers) > 0 {
grp.app.register("USE", prefix, args...) grp.app.register("USE", newPrefix, handlers...)
} }
return &Group{ return &Group{
prefix: prefix, prefix: newPrefix,
app: grp.app, app: grp.app,
} }
} }
// Static ... // Static : https://fiber.wiki/application#static
func (grp *Group) Static(args ...string) *Group { func (grp *Group) Static(args ...string) *Group {
grp.app.registerStatic(grp.prefix, args...) grp.app.registerStatic(grp.prefix, args...)
return grp return grp
} }
// WebSocket ... // WebSocket : https://fiber.wiki/application#websocket
func (grp *Group) WebSocket(args ...interface{}) *Group { func (grp *Group) WebSocket(args ...interface{}) *Group {
grp.app.register("GET", grp.prefix, args...) grp.app.register(http.MethodGet, grp.prefix, args...)
return grp return grp
} }
// Connect ... // Connect : https://fiber.wiki/application#http-methods
func (grp *Group) Connect(args ...interface{}) *Group { func (grp *Group) Connect(args ...interface{}) *Group {
grp.app.register("CONNECT", grp.prefix, args...) grp.app.register(http.MethodConnect, grp.prefix, args...)
return grp return grp
} }
// Put ... // Put : https://fiber.wiki/application#http-methods
func (grp *Group) Put(args ...interface{}) *Group { func (grp *Group) Put(args ...interface{}) *Group {
grp.app.register("PUT", grp.prefix, args...) grp.app.register(http.MethodPut, grp.prefix, args...)
return grp return grp
} }
// Post ... // Post : https://fiber.wiki/application#http-methods
func (grp *Group) Post(args ...interface{}) *Group { func (grp *Group) Post(args ...interface{}) *Group {
grp.app.register("POST", grp.prefix, args...) grp.app.register(http.MethodPost, grp.prefix, args...)
return grp return grp
} }
// Delete ... // Delete : https://fiber.wiki/application#http-methods
func (grp *Group) Delete(args ...interface{}) *Group { func (grp *Group) Delete(args ...interface{}) *Group {
grp.app.register("DELETE", grp.prefix, args...) grp.app.register(http.MethodDelete, grp.prefix, args...)
return grp return grp
} }
// Head ... // Head : https://fiber.wiki/application#http-methods
func (grp *Group) Head(args ...interface{}) *Group { func (grp *Group) Head(args ...interface{}) *Group {
grp.app.register("HEAD", grp.prefix, args...) grp.app.register(http.MethodHead, grp.prefix, args...)
return grp return grp
} }
// Patch ... // Patch : https://fiber.wiki/application#http-methods
func (grp *Group) Patch(args ...interface{}) *Group { func (grp *Group) Patch(args ...interface{}) *Group {
grp.app.register("PATCH", grp.prefix, args...) grp.app.register(http.MethodPatch, grp.prefix, args...)
return grp return grp
} }
// Options ... // Options : https://fiber.wiki/application#http-methods
func (grp *Group) Options(args ...interface{}) *Group { func (grp *Group) Options(args ...interface{}) *Group {
grp.app.register("OPTIONS", grp.prefix, args...) grp.app.register(http.MethodOptions, grp.prefix, args...)
return grp return grp
} }
// Trace ... // Trace : https://fiber.wiki/application#http-methods
func (grp *Group) Trace(args ...interface{}) *Group { func (grp *Group) Trace(args ...interface{}) *Group {
grp.app.register("TRACE", grp.prefix, args...) grp.app.register(http.MethodTrace, grp.prefix, args...)
return grp return grp
} }
// Get ... // Get : https://fiber.wiki/application#http-methods
func (grp *Group) Get(args ...interface{}) *Group { func (grp *Group) Get(args ...interface{}) *Group {
grp.app.register("GET", grp.prefix, args...) grp.app.register(http.MethodGet, grp.prefix, args...)
return grp return grp
} }
// All ... // All : https://fiber.wiki/application#http-methods
func (grp *Group) All(args ...interface{}) *Group { func (grp *Group) All(args ...interface{}) *Group {
grp.app.register("ALL", grp.prefix, args...) grp.app.register("ALL", grp.prefix, args...)
return grp return grp
} }
// Use ... // Use : https://fiber.wiki/application#http-methods
func (grp *Group) Use(args ...interface{}) *Group { func (grp *Group) Use(args ...interface{}) *Group {
grp.app.register("USE", grp.prefix, args...) grp.app.register("USE", grp.prefix, args...)
return grp return grp

View File

@ -278,7 +278,11 @@ func (app *App) handler(fctx *fasthttp.RequestCtx) {
if app.recover != nil { if app.recover != nil {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
ctx.error = fmt.Errorf("panic: %v", r) err, ok := r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
ctx.error = err
app.recover(ctx) app.recover(ctx)
} }
}() }()

View File

@ -29,21 +29,6 @@ var socketUpgrade = websocket.FastHTTPUpgrader{
}, },
} }
// MIME types
const (
MIMEApplicationJSON = "application/json"
MIMEApplicationJavaScript = "application/javascript"
MIMEApplicationXML = "application/xml"
MIMETextXML = "text/xml"
MIMEApplicationForm = "application/x-www-form-urlencoded"
MIMEApplicationProtobuf = "application/protobuf"
MIMEApplicationMsgpack = "application/msgpack"
MIMETextHTML = "text/html"
MIMETextPlain = "text/plain"
MIMEMultipartForm = "multipart/form-data"
MIMEOctetStream = "application/octet-stream"
)
func getParams(path string) (params []string) { func getParams(path string) (params []string) {
if len(path) < 1 { if len(path) < 1 {
return return
@ -125,7 +110,7 @@ func getStatus(status int) (msg string) {
// #nosec G103 // #nosec G103
// getString converts byte slice to a string without memory allocation. // getString converts byte slice to a string without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ . // See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
func getString(b []byte) string { var getString = func(b []byte) string {
return *(*string)(unsafe.Pointer(&b)) return *(*string)(unsafe.Pointer(&b))
} }
@ -157,6 +142,21 @@ func (c *testConn) SetDeadline(t time.Time) error { return nil }
func (c *testConn) SetReadDeadline(t time.Time) error { return nil } func (c *testConn) SetReadDeadline(t time.Time) error { return nil }
func (c *testConn) SetWriteDeadline(t time.Time) error { return nil } func (c *testConn) SetWriteDeadline(t time.Time) error { return nil }
// MIME types
const (
MIMEApplicationJSON = "application/json"
MIMEApplicationJavaScript = "application/javascript"
MIMEApplicationXML = "application/xml"
MIMETextXML = "text/xml"
MIMEApplicationForm = "application/x-www-form-urlencoded"
MIMEApplicationProtobuf = "application/protobuf"
MIMEApplicationMsgpack = "application/msgpack"
MIMETextHTML = "text/html"
MIMETextPlain = "text/plain"
MIMEMultipartForm = "multipart/form-data"
MIMEOctetStream = "application/octet-stream"
)
// HTTP status codes // HTTP status codes
var statusMessage = map[int]string{ var statusMessage = map[int]string{
100: "Continue", 100: "Continue",
@ -221,7 +221,7 @@ var statusMessage = map[int]string{
511: "Network Authentication Required", 511: "Network Authentication Required",
} }
// MIME types for file extensions // File extensions MIME types
var extensionMIME = map[string]string{ var extensionMIME = map[string]string{
"html": "text/html", "html": "text/html",
"htm": "text/html", "htm": "text/html",