mirror of
https://github.com/gofiber/fiber.git
synced 2025-02-14 13:46:23 +00:00
Add RenderEngine & DisableHeaderNormalizing
- RenderEngine setting - DisableHeaderNormalizing setting - Move sync pool to *App - Return *Route Co-Authored-By: RW <renewerner87@googlemail.com>
This commit is contained in:
parent
932b3c61f6
commit
6cd50c9e7b
321
app.go
321
app.go
@ -21,6 +21,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
utils "github.com/gofiber/utils"
|
||||
fasthttp "github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
@ -32,120 +33,161 @@ type Map map[string]interface{}
|
||||
|
||||
// App denotes the Fiber application.
|
||||
type App struct {
|
||||
// Layer stack
|
||||
stack [][]*Layer
|
||||
mutex sync.Mutex
|
||||
// Route stack
|
||||
stack [][]*Route
|
||||
// Ctx pool
|
||||
pool sync.Pool
|
||||
// Fasthttp server
|
||||
server *fasthttp.Server
|
||||
mutex sync.Mutex
|
||||
// App settings
|
||||
Settings *Settings
|
||||
}
|
||||
|
||||
// Enables automatic redirection if the current route can't be matched but a handler for the path with (without) the trailing slash exists. For example if /foo/ is requested but a route only exists for /foo, the client is redirected to /foo with http status code 301 for GET requests and 308 for all other request methods.
|
||||
|
||||
// Settings holds is a struct holding the server settings
|
||||
type Settings struct {
|
||||
// This will spawn multiple Go processes listening on the same port
|
||||
Prefork bool // default: false
|
||||
|
||||
// Enable strict routing. When enabled, the router treats "/foo" and "/foo/" as different.
|
||||
StrictRouting bool // default: false
|
||||
// Enable case sensitivity. When enabled, "/Foo" and "/foo" are different routes.
|
||||
CaseSensitive bool // default: false
|
||||
// By default this is disabled and both "/foo" and "/foo/" will execute the same handler.
|
||||
StrictRouting bool
|
||||
|
||||
// Enable case sensitive routing. When enabled, "/FoO" and "/foo" are different routes.
|
||||
// By default this is disabled and both "/FoO" and "/foo" will execute the same handler.
|
||||
CaseSensitive bool
|
||||
|
||||
// Enables the "Server: value" HTTP header.
|
||||
ServerHeader string // default: ""
|
||||
|
||||
// Enables handler values to be immutable even if you return from handler
|
||||
Immutable bool // default: false
|
||||
|
||||
// Enable or disable ETag header generation, since both weak and strong etags are generated
|
||||
// using the same hashing method (CRC-32). Weak ETags are the default when enabled.
|
||||
// Optional. Default value false
|
||||
ETag bool
|
||||
|
||||
// Max body size that the server accepts
|
||||
BodyLimit int // default: 4 * 1024 * 1024
|
||||
|
||||
// Maximum number of concurrent connections.
|
||||
Concurrency int // default: 256 * 1024
|
||||
|
||||
// Disable keep-alive connections, the server will close incoming connections after sending the first response to client
|
||||
DisableKeepalive bool // default: false
|
||||
|
||||
// When set to true causes the default date header to be excluded from the response.
|
||||
DisableDefaultDate bool // default: false
|
||||
|
||||
// When set to true, causes the default Content-Type header to be excluded from the Response.
|
||||
DisableDefaultContentType bool // default: false
|
||||
DisableHeaderNormalizing bool // default: false
|
||||
|
||||
// By default all header names are normalized: conteNT-tYPE -> Content-Type
|
||||
DisableHeaderNormalizing bool // default: false
|
||||
|
||||
// When set to true, it will not print out the fiber ASCII and "listening" on message
|
||||
DisableStartupMessage bool
|
||||
// Folder containing template files
|
||||
TemplateFolder string // default: ""
|
||||
// Template engine: html, amber, handlebars , mustache or pug
|
||||
TemplateEngine func(raw string, bind interface{}) (string, error) // default: nil
|
||||
// Extension for the template files
|
||||
TemplateExtension string // default: ""
|
||||
|
||||
// RenderEngine is the interface that wraps the Render function.
|
||||
RenderEngine RenderEngine
|
||||
|
||||
// The amount of time allowed to read the full request including body.
|
||||
ReadTimeout time.Duration // default: unlimited
|
||||
|
||||
// The maximum duration before timing out writes of the response.
|
||||
WriteTimeout time.Duration // default: unlimited
|
||||
|
||||
// The maximum amount of time to wait for the next request when keep-alive is enabled.
|
||||
IdleTimeout time.Duration // default: unlimited
|
||||
}
|
||||
|
||||
// Group struct
|
||||
type Group struct {
|
||||
prefix string
|
||||
app *App
|
||||
// TODO: v1.11
|
||||
// The router executes the same handler by default if StrictRouting or CaseSensitive is disabled.
|
||||
// Enabling RedirectFixedPath will change this behaviour into a client redirect to the original route path.
|
||||
// Using the status code 301 for GET requests and 308 for all other request methods.
|
||||
// RedirectFixedPath bool
|
||||
}
|
||||
|
||||
// Static struct
|
||||
type Static struct {
|
||||
// Transparently compresses responses if set to true
|
||||
// This works differently than the github.com/gofiber/compression middleware
|
||||
// The server tries minimizing CPU usage by caching compressed files.
|
||||
// It adds ".fiber.gz" suffix to the original file name.
|
||||
// Optional. Default value false
|
||||
Compress bool
|
||||
|
||||
// Enables byte range requests if set to true.
|
||||
// Optional. Default value false
|
||||
ByteRange bool
|
||||
|
||||
// Enable directory browsing.
|
||||
// Optional. Default value false.
|
||||
Browse bool
|
||||
|
||||
// Index file for serving a directory.
|
||||
// Optional. Default value "index.html".
|
||||
Index string
|
||||
}
|
||||
|
||||
// TODO: v1.11 Potential feature to get all registered routes
|
||||
// func (app *App) Routes(print ...bool) map[string][]string {
|
||||
// routes := make(map[string][]string)
|
||||
// for i := range app.stack {
|
||||
// method := intMethod[i]
|
||||
// routes[method] = []string{}
|
||||
// for k := range app.stack[i] {
|
||||
// routes[method] = append(routes[method], app.stack[i][k].Path)
|
||||
// }
|
||||
// }
|
||||
// if len(print) > 0 && print[0] {
|
||||
// b, _ := json.MarshalIndent(routes, "", " ")
|
||||
// fmt.Print(string(b))
|
||||
// }
|
||||
// return routes
|
||||
// }
|
||||
|
||||
// New creates a new Fiber named instance.
|
||||
// You can pass optional settings when creating a new instance.
|
||||
func New(settings ...*Settings) *App {
|
||||
schemaDecoderForm.SetAliasTag("form")
|
||||
schemaDecoderForm.IgnoreUnknownKeys(true)
|
||||
schemaDecoderQuery.SetAliasTag("query")
|
||||
schemaDecoderQuery.IgnoreUnknownKeys(true)
|
||||
// Create app
|
||||
app := new(App)
|
||||
// Create route stack
|
||||
app.stack = make([][]*Layer, len(methodINT))
|
||||
// Create settings
|
||||
app.Settings = new(Settings)
|
||||
// Set default settings
|
||||
app.Settings.Prefork = getArgument("-prefork")
|
||||
app.Settings.BodyLimit = 4 * 1024 * 1024
|
||||
// If settings exist, set defaults
|
||||
// Create a new app
|
||||
app := &App{
|
||||
// Create router stack
|
||||
stack: make([][]*Route, len(methodINT)),
|
||||
// Create Ctx pool
|
||||
pool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(Ctx)
|
||||
},
|
||||
},
|
||||
// Set default settings
|
||||
Settings: &Settings{
|
||||
Prefork: utils.GetArgument("-prefork"),
|
||||
BodyLimit: 4 * 1024 * 1024,
|
||||
Concurrency: 256 * 1024,
|
||||
},
|
||||
}
|
||||
// Overwrite settings if provided
|
||||
if len(settings) > 0 {
|
||||
app.Settings = settings[0] // Set custom settings
|
||||
app.Settings = settings[0]
|
||||
if !app.Settings.Prefork { // Default to -prefork flag if false
|
||||
app.Settings.Prefork = getArgument("-prefork")
|
||||
app.Settings.Prefork = utils.GetArgument("-prefork")
|
||||
}
|
||||
if app.Settings.BodyLimit <= 0 { // Default MaxRequestBodySize
|
||||
if app.Settings.BodyLimit <= 0 {
|
||||
app.Settings.BodyLimit = 4 * 1024 * 1024
|
||||
}
|
||||
if app.Settings.Concurrency <= 0 {
|
||||
app.Settings.Concurrency = 256 * 1024
|
||||
}
|
||||
if app.Settings.Immutable { // Replace unsafe conversion funcs
|
||||
getString = getStringImmutable
|
||||
// Replace unsafe conversion functions
|
||||
if app.Settings.Immutable {
|
||||
getBytes = getBytesImmutable
|
||||
getString = getStringImmutable
|
||||
}
|
||||
}
|
||||
// Create server
|
||||
app.init()
|
||||
// Return application
|
||||
return app
|
||||
// Initialize app
|
||||
return app.init()
|
||||
}
|
||||
|
||||
// Use registers a middleware route.
|
||||
@ -155,7 +197,7 @@ func New(settings ...*Settings) *App {
|
||||
// - app.Use(handler)
|
||||
// - app.Use("/api", handler)
|
||||
// - app.Use("/api", handler, handler)
|
||||
func (app *App) Use(args ...interface{}) *App {
|
||||
func (app *App) Use(args ...interface{}) *Route {
|
||||
var prefix string
|
||||
var handlers []func(*Ctx)
|
||||
|
||||
@ -172,194 +214,76 @@ func (app *App) Use(args ...interface{}) *App {
|
||||
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...)
|
||||
func (app *App) Get(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodGet, path, handlers...)
|
||||
}
|
||||
|
||||
// Head ...
|
||||
func (app *App) Head(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodHead, path, handlers...)
|
||||
func (app *App) Head(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodHead, path, handlers...)
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (app *App) Post(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodPost, path, handlers...)
|
||||
func (app *App) Post(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodPost, path, handlers...)
|
||||
}
|
||||
|
||||
// Put ...
|
||||
func (app *App) Put(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodPut, path, handlers...)
|
||||
func (app *App) Put(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodPut, path, handlers...)
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (app *App) Delete(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodDelete, path, handlers...)
|
||||
func (app *App) Delete(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodDelete, path, handlers...)
|
||||
}
|
||||
|
||||
// Connect ...
|
||||
func (app *App) Connect(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodConnect, path, handlers...)
|
||||
func (app *App) Connect(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodConnect, path, handlers...)
|
||||
}
|
||||
|
||||
// Options ...
|
||||
func (app *App) Options(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodOptions, path, handlers...)
|
||||
func (app *App) Options(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodOptions, path, handlers...)
|
||||
}
|
||||
|
||||
// Trace ...
|
||||
func (app *App) Trace(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodTrace, path, handlers...)
|
||||
func (app *App) Trace(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(MethodTrace, path, handlers...)
|
||||
}
|
||||
|
||||
// Patch ...
|
||||
func (app *App) Patch(path string, handlers ...func(*Ctx)) *App {
|
||||
return app.register(MethodPatch, path, handlers...)
|
||||
func (app *App) Patch(path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.Add(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)
|
||||
}
|
||||
func (app *App) Add(method, path string, handlers ...func(*Ctx)) *Route {
|
||||
return app.register(method, path, handlers...)
|
||||
}
|
||||
|
||||
// Static ...
|
||||
func (app *App) Static(prefix, root string, config ...Static) *Route {
|
||||
return app.registerStatic(prefix, root, config...)
|
||||
}
|
||||
|
||||
// All ...
|
||||
func (app *App) All(path string, handlers ...func(*Ctx)) []*Route {
|
||||
routes := make([]*Route, len(methodINT))
|
||||
for method, i := range methodINT {
|
||||
routes[i] = app.Add(method, path, handlers...)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if len(handlers) > 0 {
|
||||
app.register("USE", prefix, handlers...)
|
||||
}
|
||||
return &Group{
|
||||
prefix: prefix,
|
||||
app: app,
|
||||
}
|
||||
}
|
||||
|
||||
// Static registers a new route with path prefix to serve static files from the provided root directory.
|
||||
func (app *App) Static(prefix, root string, config ...Static) *App {
|
||||
app.registerStatic(prefix, root, config...)
|
||||
return app
|
||||
}
|
||||
|
||||
// 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 {
|
||||
prefix = getGroupPath(grp.prefix, prefix)
|
||||
if len(handlers) > 0 {
|
||||
grp.app.register("USE", prefix, handlers...)
|
||||
}
|
||||
return &Group{
|
||||
prefix: prefix,
|
||||
app: grp.app,
|
||||
}
|
||||
}
|
||||
|
||||
// Static : https://fiber.wiki/application#static
|
||||
func (grp *Group) Static(prefix, root string, config ...Static) *Group {
|
||||
prefix = getGroupPath(grp.prefix, prefix)
|
||||
grp.app.registerStatic(prefix, root, config...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Use registers a middleware route.
|
||||
// Middleware matches requests beginning with the provided prefix.
|
||||
// Providing a prefix is optional, it defaults to "/"
|
||||
func (grp *Group) Use(args ...interface{}) *Group {
|
||||
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 Use() arguments, must be (prefix, handler) or (handler)")
|
||||
}
|
||||
}
|
||||
grp.app.register("USE", getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Add : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Add(method, path string, handlers ...func(*Ctx)) *Group {
|
||||
method = toUpper(method)
|
||||
if methodINT[method] == 0 && method != MethodGet {
|
||||
log.Fatalf("Add: Invalid HTTP method %s", method)
|
||||
}
|
||||
grp.app.register(method, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Connect : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Connect(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodConnect, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Put : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Put(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodPut, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Post : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Post(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodPost, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Delete : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Delete(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodDelete, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Head : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Head(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodHead, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Patch : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Patch(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodPatch, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Options : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Options(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodOptions, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Trace : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Trace(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodTrace, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// Get : https://fiber.wiki/application#http-methods
|
||||
func (grp *Group) Get(path string, handlers ...func(*Ctx)) *Group {
|
||||
grp.app.register(MethodGet, getGroupPath(grp.prefix, path), handlers...)
|
||||
return grp
|
||||
}
|
||||
|
||||
// All matches all HTTP methods and complete paths
|
||||
func (grp *Group) All(path string, handlers ...func(*Ctx)) *Group {
|
||||
for m := range methodINT {
|
||||
grp.app.register(m, getGroupPath(grp.prefix, path), handlers...)
|
||||
}
|
||||
return grp
|
||||
return &Group{prefix: prefix, app: app}
|
||||
}
|
||||
|
||||
// Serve can be used to pass a custom listener
|
||||
@ -415,7 +339,7 @@ func (app *App) Listen(address interface{}, tlsconfig ...*tls.Config) error {
|
||||
ln = tls.NewListener(ln, tlsconfig[0])
|
||||
}
|
||||
// Print listening message
|
||||
if !app.Settings.DisableStartupMessage && !getArgument("-child") {
|
||||
if !app.Settings.DisableStartupMessage && !utils.GetArgument("-child") {
|
||||
fmt.Printf(" _______ __\n ____ / ____(_) /_ ___ _____\n_____ / /_ / / __ \\/ _ \\/ ___/\n __ / __/ / / /_/ / __/ /\n /_/ /_/_.___/\\___/_/ v%s\n", Version)
|
||||
fmt.Printf("Started listening on %s\n", ln.Addr().String())
|
||||
}
|
||||
@ -497,7 +421,7 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
|
||||
// Sharding: https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
|
||||
func (app *App) prefork(address string) (ln net.Listener, err error) {
|
||||
// Master proc
|
||||
if !getArgument("-child") {
|
||||
if !utils.GetArgument("-child") {
|
||||
addr, err := net.ResolveTCPAddr("tcp", address)
|
||||
if err != nil {
|
||||
return ln, err
|
||||
@ -543,7 +467,7 @@ func (dl *disableLogger) Printf(format string, args ...interface{}) {
|
||||
// fmt.Println(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (app *App) init() {
|
||||
func (app *App) init() *App {
|
||||
app.mutex.Lock()
|
||||
if app.server == nil {
|
||||
app.server = &fasthttp.Server{
|
||||
@ -581,4 +505,5 @@ func (app *App) init() {
|
||||
app.server.WriteTimeout = app.Settings.WriteTimeout
|
||||
app.server.IdleTimeout = app.Settings.IdleTimeout
|
||||
app.mutex.Unlock()
|
||||
return app
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user