fresh with main branch

generic_app_ctx_3221
René 2025-03-26 14:38:58 +01:00
parent 334612f5b2
commit b48acd937d
6 changed files with 69 additions and 105 deletions

View File

@ -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
}

View File

@ -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] {

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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
}