Refactor internal functions

pull/386/head
Fenny 2020-05-16 05:11:25 +02:00
parent 0069c1b92e
commit 3fb483e9df
1 changed files with 155 additions and 148 deletions

303
app.go
View File

@ -25,22 +25,20 @@ import (
) )
// Version of current package // Version of current package
const Version = "1.9.7" const Version = "1.10.0"
// Map is a shortcut for map[string]interface{} // Map is a shortcut for map[string]interface{}, usefull for JSON returns
type Map map[string]interface{} type Map map[string]interface{}
// App denotes the Fiber application. // App denotes the Fiber application.
type App struct { type App struct {
// Internal fields // Layer stack
routes [][]*Route // Route stack stack [][]*Layer
// External fields
Settings *Settings // Fiber settings
// Fasthttp server // Fasthttp server
mutex sync.Mutex // Mutual exclusion server *fasthttp.Server
server *fasthttp.Server // FastHTTP server mutex sync.Mutex
// App settings
Settings *Settings
} }
// Settings holds is a struct holding the server settings // Settings holds is a struct holding the server settings
@ -69,6 +67,7 @@ type Settings struct {
DisableDefaultDate bool // default: false DisableDefaultDate bool // default: false
// When set to true, causes the default Content-Type header to be excluded from the Response. // When set to true, causes the default Content-Type header to be excluded from the Response.
DisableDefaultContentType bool // default: false DisableDefaultContentType bool // default: false
DisableHeaderNormalizing bool // default: false
// When set to true, it will not print out the fiber ASCII and "listening" on message // When set to true, it will not print out the fiber ASCII and "listening" on message
DisableStartupMessage bool DisableStartupMessage bool
// Folder containing template files // Folder containing template files
@ -120,7 +119,7 @@ func New(settings ...*Settings) *App {
// Create app // Create app
app := new(App) app := new(App)
// Create route stack // Create route stack
app.routes = make([][]*Route, len(methodINT)) app.stack = make([][]*Layer, len(methodINT))
// Create settings // Create settings
app.Settings = new(Settings) app.Settings = new(Settings)
// Set default settings // Set default settings
@ -143,16 +142,102 @@ func New(settings ...*Settings) *App {
getBytes = getBytesImmutable getBytes = getBytesImmutable
} }
} }
// Update fiber server settings with fasthttp server // Create server
app.updateSettings() app.init()
// Return application // Return application
return app return app
} }
// Use registers a middleware route.
// Middleware matches requests beginning with the provided prefix.
// Providing a prefix is optional, it defaults to "/".
//
// - app.Use(handler)
// - app.Use("/api", handler)
// - app.Use("/api", handler, handler)
func (app *App) Use(args ...interface{}) *App {
var prefix string
var handlers []func(*Ctx)
for i := 0; i < len(args); i++ {
switch arg := args[i].(type) {
case string:
prefix = arg
case func(*Ctx):
handlers = append(handlers, arg)
default:
log.Fatalf("Use: Invalid func(c *fiber.Ctx) handler %v", reflect.TypeOf(arg))
}
}
return app.register("USE", prefix, handlers...)
}
// All ...
func (app *App) All(path string, handlers ...func(*Ctx)) *App {
for m := range methodINT {
app.register(m, path, handlers...)
}
return app
}
// Get ...
func (app *App) Get(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodGet, path, handlers...)
}
// Head ...
func (app *App) Head(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodHead, path, handlers...)
}
// Post ...
func (app *App) Post(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodPost, path, handlers...)
}
// Put ...
func (app *App) Put(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodPut, path, handlers...)
}
// Delete ...
func (app *App) Delete(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodDelete, path, handlers...)
}
// Connect ...
func (app *App) Connect(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodConnect, path, handlers...)
}
// Options ...
func (app *App) Options(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodOptions, path, handlers...)
}
// Trace ...
func (app *App) Trace(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodTrace, path, handlers...)
}
// Patch ...
func (app *App) Patch(path string, handlers ...func(*Ctx)) *App {
return app.register(MethodPatch, path, handlers...)
}
// Add ...
func (app *App) Add(method, path string, handlers ...func(*Ctx)) *App {
method = toUpper(method)
if methodINT[method] == 0 && method != MethodGet {
log.Fatalf("Add: Invalid HTTP method %s", method)
}
return app.register(method, path, handlers...)
}
// Group is used for Routes with common prefix to define a new sub-router with optional middleware. // Group is used for Routes with common prefix to define a new sub-router with optional middleware.
func (app *App) Group(prefix string, handlers ...func(*Ctx)) *Group { func (app *App) Group(prefix string, handlers ...func(*Ctx)) *Group {
if len(handlers) > 0 { if len(handlers) > 0 {
app.registerMethod("USE", prefix, handlers...) app.register("USE", prefix, handlers...)
} }
return &Group{ return &Group{
prefix: prefix, prefix: prefix,
@ -166,101 +251,11 @@ func (app *App) Static(prefix, root string, config ...Static) *App {
return app return app
} }
// Use registers a middleware route.
// Middleware matches requests beginning with the provided prefix.
// Providing a prefix is optional, it defaults to "/"
func (app *App) Use(args ...interface{}) *App {
var path = ""
var handlers []func(*Ctx)
for i := 0; i < len(args); i++ {
switch arg := args[i].(type) {
case string:
path = arg
case func(*Ctx):
handlers = append(handlers, arg)
default:
log.Fatalf("Invalid handler: %v", reflect.TypeOf(arg))
}
}
app.registerMethod("USE", path, handlers...)
return app
}
// Add : https://fiber.wiki/application#http-methods
func (app *App) Add(method, path string, handlers ...func(*Ctx)) *App {
method = strings.ToUpper(method)
if methodINT[method] == 0 && method != "GET" {
log.Fatalf("Add: Invalid HTTP method %s", method)
}
app.registerMethod(method, path, handlers...)
return app
}
// Connect : https://fiber.wiki/application#http-methods
func (app *App) Connect(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodConnect, path, handlers...)
return app
}
// Put : https://fiber.wiki/application#http-methods
func (app *App) Put(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodPut, path, handlers...)
return app
}
// Post : https://fiber.wiki/application#http-methods
func (app *App) Post(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodPost, path, handlers...)
return app
}
// Delete : https://fiber.wiki/application#http-methods
func (app *App) Delete(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodDelete, path, handlers...)
return app
}
// Head : https://fiber.wiki/application#http-methods
func (app *App) Head(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodHead, path, handlers...)
return app
}
// Patch : https://fiber.wiki/application#http-methods
func (app *App) Patch(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodPatch, path, handlers...)
return app
}
// Options : https://fiber.wiki/application#http-methods
func (app *App) Options(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodOptions, path, handlers...)
return app
}
// Trace : https://fiber.wiki/application#http-methods
func (app *App) Trace(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodTrace, path, handlers...)
return app
}
// Get : https://fiber.wiki/application#http-methods
func (app *App) Get(path string, handlers ...func(*Ctx)) *App {
app.registerMethod(MethodGet, path, handlers...)
return app
}
// All matches all HTTP methods and complete paths
func (app *App) All(path string, handlers ...func(*Ctx)) *App {
app.registerMethod("ALL", path, handlers...)
return app
}
// Group is used for Routes with common prefix to define a new sub-router with optional middleware. // Group is used for Routes with common prefix to define a new sub-router with optional middleware.
func (grp *Group) Group(prefix string, handlers ...func(*Ctx)) *Group { func (grp *Group) Group(prefix string, handlers ...func(*Ctx)) *Group {
prefix = getGroupPath(grp.prefix, prefix) prefix = getGroupPath(grp.prefix, prefix)
if len(handlers) > 0 { if len(handlers) > 0 {
grp.app.registerMethod("USE", prefix, handlers...) grp.app.register("USE", prefix, handlers...)
} }
return &Group{ return &Group{
prefix: prefix, prefix: prefix,
@ -288,80 +283,82 @@ func (grp *Group) Use(args ...interface{}) *Group {
case func(*Ctx): case func(*Ctx):
handlers = append(handlers, arg) handlers = append(handlers, arg)
default: default:
log.Fatalf("Invalid Use() arguments, must be (prefix, handler) or (handler)") //log.Fatalf("Invalid Use() arguments, must be (prefix, handler) or (handler)")
} }
} }
grp.app.registerMethod("USE", getGroupPath(grp.prefix, path), handlers...) grp.app.register("USE", getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Add : https://fiber.wiki/application#http-methods // Add : https://fiber.wiki/application#http-methods
func (grp *Group) Add(method, path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Add(method, path string, handlers ...func(*Ctx)) *Group {
method = strings.ToUpper(method) method = toUpper(method)
if methodINT[method] == 0 && method != "GET" { if methodINT[method] == 0 && method != MethodGet {
log.Fatalf("Add: Invalid HTTP method %s", method) log.Fatalf("Add: Invalid HTTP method %s", method)
} }
grp.app.registerMethod(method, getGroupPath(grp.prefix, path), handlers...) grp.app.register(method, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Connect : https://fiber.wiki/application#http-methods // Connect : https://fiber.wiki/application#http-methods
func (grp *Group) Connect(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Connect(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodConnect, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodConnect, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Put : https://fiber.wiki/application#http-methods // Put : https://fiber.wiki/application#http-methods
func (grp *Group) Put(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Put(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodPut, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodPut, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Post : https://fiber.wiki/application#http-methods // Post : https://fiber.wiki/application#http-methods
func (grp *Group) Post(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Post(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodPost, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodPost, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Delete : https://fiber.wiki/application#http-methods // Delete : https://fiber.wiki/application#http-methods
func (grp *Group) Delete(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Delete(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodDelete, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodDelete, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Head : https://fiber.wiki/application#http-methods // Head : https://fiber.wiki/application#http-methods
func (grp *Group) Head(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Head(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodHead, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodHead, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Patch : https://fiber.wiki/application#http-methods // Patch : https://fiber.wiki/application#http-methods
func (grp *Group) Patch(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Patch(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodPatch, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodPatch, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Options : https://fiber.wiki/application#http-methods // Options : https://fiber.wiki/application#http-methods
func (grp *Group) Options(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Options(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodOptions, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodOptions, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Trace : https://fiber.wiki/application#http-methods // Trace : https://fiber.wiki/application#http-methods
func (grp *Group) Trace(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Trace(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodTrace, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodTrace, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// Get : https://fiber.wiki/application#http-methods // Get : https://fiber.wiki/application#http-methods
func (grp *Group) Get(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) Get(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod(MethodGet, getGroupPath(grp.prefix, path), handlers...) grp.app.register(MethodGet, getGroupPath(grp.prefix, path), handlers...)
return grp return grp
} }
// All matches all HTTP methods and complete paths // All matches all HTTP methods and complete paths
func (grp *Group) All(path string, handlers ...func(*Ctx)) *Group { func (grp *Group) All(path string, handlers ...func(*Ctx)) *Group {
grp.app.registerMethod("ALL", getGroupPath(grp.prefix, path), handlers...) for m := range methodINT {
grp.app.register(m, getGroupPath(grp.prefix, path), handlers...)
}
return grp return grp
} }
@ -371,7 +368,7 @@ func (grp *Group) All(path string, handlers ...func(*Ctx)) *Group {
// You can pass an optional *tls.Config to enable TLS. // You can pass an optional *tls.Config to enable TLS.
func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error { func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error {
// Update fiber server settings // Update fiber server settings
app.updateSettings() app.init()
// TLS config // TLS config
if len(tlsconfig) > 0 { if len(tlsconfig) > 0 {
ln = tls.NewListener(ln, tlsconfig[0]) ln = tls.NewListener(ln, tlsconfig[0])
@ -399,7 +396,7 @@ func (app *App) Listen(address interface{}, tlsconfig ...*tls.Config) error {
addr = ":" + addr addr = ":" + addr
} }
// Update fiber server settings // Update fiber server settings
app.updateSettings() app.init()
// Setup listener // Setup listener
var ln net.Listener var ln net.Listener
var err error var err error
@ -454,7 +451,7 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
return nil, err return nil, err
} }
// Update server settings // Update server settings
app.updateSettings() app.init()
// Create test connection // Create test connection
conn := new(testConn) conn := new(testConn)
// Write raw http request // Write raw http request
@ -542,32 +539,42 @@ func (dl *disableLogger) Printf(format string, args ...interface{}) {
// fmt.Println(fmt.Sprintf(format, args...)) // fmt.Println(fmt.Sprintf(format, args...))
} }
func (app *App) updateSettings() { func (app *App) init() {
// Create fasthttp server
app.mutex.Lock() app.mutex.Lock()
app.server = &fasthttp.Server{ if app.server == nil {
Handler: app.handler, app.server = &fasthttp.Server{
Name: app.Settings.ServerHeader, Logger: &disableLogger{},
Concurrency: app.Settings.Concurrency, LogAllErrors: false,
NoDefaultDate: app.Settings.DisableDefaultDate, ErrorHandler: func(fctx *fasthttp.RequestCtx, err error) {
NoDefaultContentType: app.Settings.DisableDefaultContentType, if _, ok := err.(*fasthttp.ErrSmallBuffer); ok {
DisableKeepalive: app.Settings.DisableKeepalive, fctx.Response.SetStatusCode(StatusRequestHeaderFieldsTooLarge)
MaxRequestBodySize: app.Settings.BodyLimit, fctx.Response.SetBodyString("Request Header Fields Too Large")
NoDefaultServerHeader: app.Settings.ServerHeader == "", } else if netErr, ok := err.(*net.OpError); ok && netErr.Timeout() {
ReadTimeout: app.Settings.ReadTimeout, fctx.Response.SetStatusCode(StatusRequestTimeout)
WriteTimeout: app.Settings.WriteTimeout, fctx.Response.SetBodyString("Request Timeout")
IdleTimeout: app.Settings.IdleTimeout, } else if len(err.Error()) == 33 && err.Error() == "body size exceeds the given limit" {
Logger: &disableLogger{}, fctx.Response.SetStatusCode(StatusRequestEntityTooLarge)
LogAllErrors: false, fctx.Response.SetBodyString("Request Entity Too Large")
ErrorHandler: func(ctx *fasthttp.RequestCtx, err error) { } else {
if err.Error() == "body size exceeds the given limit" { fctx.Response.SetStatusCode(StatusBadRequest)
ctx.Response.SetStatusCode(StatusRequestEntityTooLarge) fctx.Response.SetBodyString("Bad Request")
ctx.Response.SetBodyString("Request Entity Too Large") }
} else { },
ctx.Response.SetStatusCode(StatusBadRequest) }
ctx.Response.SetBodyString("Bad Request")
}
},
} }
if app.server.Handler == nil {
app.server.Handler = app.handler
}
app.server.Name = app.Settings.ServerHeader
app.server.Concurrency = app.Settings.Concurrency
app.server.NoDefaultDate = app.Settings.DisableDefaultDate
app.server.NoDefaultContentType = app.Settings.DisableDefaultContentType
app.server.DisableHeaderNamesNormalizing = app.Settings.DisableHeaderNormalizing
app.server.DisableKeepalive = app.Settings.DisableKeepalive
app.server.MaxRequestBodySize = app.Settings.BodyLimit
app.server.NoDefaultServerHeader = app.Settings.ServerHeader == ""
app.server.ReadTimeout = app.Settings.ReadTimeout
app.server.WriteTimeout = app.Settings.WriteTimeout
app.server.IdleTimeout = app.Settings.IdleTimeout
app.mutex.Unlock() app.mutex.Unlock()
} }