mirror of https://github.com/gofiber/fiber.git
fresh with main branch
parent
334612f5b2
commit
b48acd937d
26
app_test.go
26
app_test.go
|
@ -31,8 +31,34 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"github.com/valyala/fasthttp"
|
||||
"github.com/valyala/fasthttp/fasthttputil"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type UserStatsCreateDTO struct {
|
||||
FirstName string `json:"first_name" validate:"required"`
|
||||
Age int `json:"age" validate:"required,gt=5"`
|
||||
BirthDate string `json:"birth_date" validate:"required,datetime=2006/01/02"`
|
||||
}
|
||||
|
||||
// test main func
|
||||
func Test_NewValidatorError(t *testing.T) {
|
||||
userDTO := UserStatsCreateDTO{
|
||||
FirstName: "John",
|
||||
Age: 10,
|
||||
BirthDate: "2024-01-01 12:00:00",
|
||||
}
|
||||
|
||||
validate := validator.New()
|
||||
err := validate.Struct(userDTO)
|
||||
|
||||
validationErrors := err.(validator.ValidationErrors)
|
||||
|
||||
fmt.Println(validationErrors[0].Field())
|
||||
require.Equal(t, "BirthDate", validationErrors[0].Field())
|
||||
require.Equal(t, "datetime", validationErrors[0].Tag())
|
||||
}
|
||||
|
||||
func testEmptyHandler(_ Ctx) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -32,10 +32,14 @@ type CustomCtx[T any] interface {
|
|||
|
||||
func NewDefaultCtx[TCtx *DefaultCtx](app *App[*DefaultCtx]) TCtx {
|
||||
// return ctx
|
||||
return &DefaultCtx{
|
||||
ctx := &DefaultCtx{
|
||||
// Set app reference
|
||||
app: app,
|
||||
}
|
||||
ctx.req = &DefaultReq{ctx: ctx}
|
||||
ctx.res = &DefaultRes{ctx: ctx}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (app *App[TCtx]) newCtx() CtxGeneric[TCtx] {
|
||||
|
|
|
@ -213,6 +213,7 @@ type CtxGeneric[T any] interface {
|
|||
Params(key string, defaultValue ...string) string
|
||||
// Path returns the path part of the request URL.
|
||||
// Optionally, you could override the path.
|
||||
// Make copies or use the Immutable setting to use the value outside the Handler.
|
||||
Path(override ...string) string
|
||||
// Scheme contains the request protocol string: http or https for TLS requests.
|
||||
// Please use Config.TrustProxy to prevent header spoofing, in case when your app is behind the proxy.
|
||||
|
@ -258,15 +259,21 @@ type CtxGeneric[T any] interface {
|
|||
// Variables are read by the Render method and may be overwritten.
|
||||
ViewBind(vars Map) error
|
||||
// getLocationFromRoute get URL location from route using parameters
|
||||
getLocationFromRoute(route Route[T], params Map) (string, error)
|
||||
getLocationFromRoute(route Route, params Map) (string, error)
|
||||
// GetRouteURL generates URLs to named routes, with parameters. URLs are relative, for example: "/user/1831"
|
||||
GetRouteURL(routeName string, params Map) (string, error)
|
||||
// Render a template with data and sends a text/html response.
|
||||
// We support the following engines: https://github.com/gofiber/template
|
||||
Render(name string, bind any, layouts ...string) error
|
||||
renderExtensions(bind any)
|
||||
// Req returns a convenience type whose API is limited to operations
|
||||
// on the incoming request.
|
||||
Req() Req
|
||||
// Res returns a convenience type whose API is limited to operations
|
||||
// on the outgoing response.
|
||||
Res() Res
|
||||
// Route returns the matched Route struct.
|
||||
Route() *Route[T]
|
||||
Route() *Route
|
||||
// SaveFile saves any multipart file to disk.
|
||||
SaveFile(fileheader *multipart.FileHeader, path string) error
|
||||
// SaveFileToStorage saves any multipart file to an external storage system.
|
||||
|
@ -349,47 +356,11 @@ type CtxGeneric[T any] interface {
|
|||
setIndexHandler(handler int)
|
||||
setIndexRoute(route int)
|
||||
setMatched(matched bool)
|
||||
setRoute(route *Route)
|
||||
}
|
||||
|
||||
func NewDefaultCtx(app *App) *DefaultCtx {
|
||||
// return ctx
|
||||
ctx := &DefaultCtx{
|
||||
// Set app reference
|
||||
app: app,
|
||||
}
|
||||
ctx.req = &DefaultReq{ctx: ctx}
|
||||
ctx.res = &DefaultRes{ctx: ctx}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (app *App) newCtx() Ctx {
|
||||
var c Ctx
|
||||
|
||||
if app.newCtxFunc != nil {
|
||||
c = app.newCtxFunc(app)
|
||||
} else {
|
||||
c = NewDefaultCtx(app)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// AcquireCtx retrieves a new Ctx from the pool.
|
||||
func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) Ctx {
|
||||
ctx, ok := app.pool.Get().(Ctx)
|
||||
|
||||
if !ok {
|
||||
panic(errors.New("failed to type-assert to Ctx"))
|
||||
}
|
||||
ctx.Reset(fctx)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// ReleaseCtx releases the ctx back into the pool.
|
||||
func (app *App) ReleaseCtx(c Ctx) {
|
||||
c.release()
|
||||
app.pool.Put(c)
|
||||
setRoute(route *Route[T])
|
||||
// Drop closes the underlying connection without sending any response headers or body.
|
||||
// This can be useful for silently terminating client connections, such as in DDoS mitigation
|
||||
// or when blocking access to sensitive endpoints.
|
||||
Drop() error
|
||||
// End immediately flushes the current response and closes the underlying connection.
|
||||
End() error
|
||||
}
|
||||
|
|
8
go.mod
8
go.mod
|
@ -3,6 +3,7 @@ module github.com/gofiber/fiber/v3
|
|||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/go-playground/validator/v10 v10.25.0
|
||||
github.com/gofiber/schema v1.3.0
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.7
|
||||
github.com/google/uuid v1.6.0
|
||||
|
@ -15,6 +16,13 @@ require (
|
|||
golang.org/x/crypto v0.36.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
|
|
14
go.sum
14
go.sum
|
@ -4,6 +4,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/gofiber/schema v1.3.0 h1:K3F3wYzAY+aivfCCEHPufCthu5/13r/lzp1nuk6mr3Q=
|
||||
github.com/gofiber/schema v1.3.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c=
|
||||
github.com/gofiber/utils/v2 v2.0.0-beta.7 h1:NnHFrRHvhrufPABdWajcKZejz9HnCWmT/asoxRsiEbQ=
|
||||
|
@ -12,6 +22,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
|
@ -34,8 +46,6 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ
|
|||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
59
router.go
59
router.go
|
@ -144,7 +144,7 @@ func (app *App[TCtx]) next(c TCtx) (bool, error) { //nolint:unparam // bool para
|
|||
}
|
||||
|
||||
// If c.Next() does not match, return 404
|
||||
err := NewError(StatusNotFound, "Cannot "+c.Method()+" "+c.getPathOriginal())
|
||||
err := NewError(StatusNotFound, "Cannot "+c.Method()+" "+html.EscapeString(c.getPathOriginal()))
|
||||
|
||||
// If no match, scan stack again if other methods match the request
|
||||
// Moved from app.handler because middleware may break the route chain
|
||||
|
@ -154,61 +154,6 @@ func (app *App[TCtx]) next(c TCtx) (bool, error) { //nolint:unparam // bool para
|
|||
return false, err
|
||||
}
|
||||
|
||||
func (app *App) next2222(c *DefaultCtx) (bool, error) {
|
||||
// Get stack length
|
||||
tree, ok := app.treeStack[c.methodInt][c.treePathHash]
|
||||
if !ok {
|
||||
tree = app.treeStack[c.methodInt][0]
|
||||
}
|
||||
lenTree := len(tree) - 1
|
||||
|
||||
// Loop over the route stack starting from previous index
|
||||
for c.indexRoute < lenTree {
|
||||
// Increment route index
|
||||
c.indexRoute++
|
||||
|
||||
// Get *Route
|
||||
route := tree[c.indexRoute]
|
||||
|
||||
var match bool
|
||||
var err error
|
||||
// skip for mounted apps
|
||||
if route.mount {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if it matches the request path
|
||||
match = route.match(utils.UnsafeString(c.detectionPath), utils.UnsafeString(c.path), &c.values)
|
||||
if !match {
|
||||
// No match, next route
|
||||
continue
|
||||
}
|
||||
// Pass route reference and param values
|
||||
c.route = route
|
||||
|
||||
// Non use handler matched
|
||||
if !c.matched && !route.use {
|
||||
c.matched = true
|
||||
}
|
||||
|
||||
// Execute first handler of route
|
||||
c.indexHandler = 0
|
||||
if len(route.Handlers) > 0 {
|
||||
err = route.Handlers[0](c)
|
||||
}
|
||||
return match, err // Stop scanning the stack
|
||||
}
|
||||
|
||||
// If c.Next() does not match, return 404
|
||||
err := NewError(StatusNotFound, "Cannot "+c.Method()+" "+html.EscapeString(c.pathOriginal))
|
||||
if !c.matched && app.methodExist(c) {
|
||||
// If no match, scan stack again if other methods match the request
|
||||
// Moved from app.handler because middleware may break the route chain
|
||||
err = ErrMethodNotAllowed
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (app *App[TCtx]) requestHandler(rctx *fasthttp.RequestCtx) {
|
||||
// Acquire DefaultCtx from the pool
|
||||
ctx := app.AcquireCtx(rctx)
|
||||
|
@ -216,7 +161,7 @@ func (app *App[TCtx]) requestHandler(rctx *fasthttp.RequestCtx) {
|
|||
defer app.ReleaseCtx(ctx)
|
||||
|
||||
// Check if the HTTP method is valid
|
||||
if ctx.methodInt == -1 {
|
||||
if app.methodInt(ctx.Method()) == -1 {
|
||||
_ = ctx.SendStatus(StatusNotImplemented) //nolint:errcheck // Always return nil
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue