Merge branch 'main' into cookie-sanitization

pull/3379/head
Juan Calderon-Perez 2025-04-01 08:23:41 -04:00 committed by GitHub
commit 8d7a7dcb44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 12 deletions

View File

@ -250,6 +250,10 @@ app.Get("/:test<int>?", func(c fiber.Ctx) error {
Custom constraints can be added to Fiber using the `app.RegisterCustomConstraint` method. Your constraints have to be compatible with the `CustomConstraint` interface.
:::caution
Attention, custom constraints can now override built-in constraints. If a custom constraint has the same name as a built-in constraint, the custom constraint will be used instead. This allows for more flexibility in defining route parameter constraints.
:::
It is a good idea to add external constraints to your project once you want to add more specific rules to your routes.
For example, you can add a constraint to check if a parameter is a valid ULID.

39
path.go
View File

@ -672,12 +672,25 @@ func getParamConstraintType(constraintPart string) TypeConstraint {
}
}
//nolint:errcheck // TODO: Properly check _all_ errors in here, log them & immediately return
// CheckConstraint validates if a param matches the given constraint
// Returns true if the param passes the constraint check, false otherwise
//
//nolint:errcheck // TODO: Properly check _all_ errors in here, log them or immediately return
func (c *Constraint) CheckConstraint(param string) bool {
var err error
var num int
// First check if there's a custom constraint with the same name
// This allows custom constraints to override built-in constraints
for _, cc := range c.customConstraints {
if cc.Name() == c.Name {
return cc.Execute(param, c.Data...)
}
}
// check data exists
var (
err error
num int
)
// Validate constraint has required data
needOneData := []TypeConstraint{minLenConstraint, maxLenConstraint, lenConstraint, minConstraint, maxConstraint, datetimeConstraint, regexConstraint}
needTwoData := []TypeConstraint{betweenLenConstraint, rangeConstraint}
@ -696,11 +709,7 @@ func (c *Constraint) CheckConstraint(param string) bool {
// check constraints
switch c.ID {
case noConstraint:
for _, cc := range c.customConstraints {
if cc.Name() == c.Name {
return cc.Execute(param, c.Data...)
}
}
return true
case intConstraint:
_, err = strconv.Atoi(param)
case boolConstraint:
@ -744,14 +753,14 @@ func (c *Constraint) CheckConstraint(param string) bool {
data, _ := strconv.Atoi(c.Data[0])
num, err = strconv.Atoi(param)
if num < data {
if err != nil || num < data {
return false
}
case maxConstraint:
data, _ := strconv.Atoi(c.Data[0])
num, err = strconv.Atoi(param)
if num > data {
if err != nil || num > data {
return false
}
case rangeConstraint:
@ -759,12 +768,18 @@ func (c *Constraint) CheckConstraint(param string) bool {
data2, _ := strconv.Atoi(c.Data[1])
num, err = strconv.Atoi(param)
if num < data || num > data2 {
if err != nil || num < data || num > data2 {
return false
}
case datetimeConstraint:
_, err = time.Parse(c.Data[0], param)
if err != nil {
return false
}
case regexConstraint:
if c.RegexCompiler == nil {
return false
}
if match := c.RegexCompiler.MatchString(param); !match {
return false
}

View File

@ -713,6 +713,14 @@ func init() {
{url: "/api/v1/", params: []string{""}, match: true},
},
},
// Add test case for RegexCompiler == nil
{
pattern: "/api/v1/:param<regex(\\d+)>",
testCases: []routeTestCase{
{url: "/api/v1/123", params: []string{"123"}, match: true},
{url: "/api/v1/abc", params: nil, match: false},
},
},
}...,
)
}