From e72ea32dd2515014d01b4094c47449dc8c42ba93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Tue, 30 Aug 2022 09:40:58 +0300 Subject: [PATCH] :bug: bug: fix regex constraints (#2059) --- path.go | 39 +++++++++++++++++++++++++-------------- path_test.go | 16 ++++++++++++++-- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/path.go b/path.go index db2818dd..2b9e0e45 100644 --- a/path.go +++ b/path.go @@ -7,7 +7,6 @@ package fiber import ( - "fmt" "regexp" "strconv" "strings" @@ -250,7 +249,7 @@ func (routeParser *routeParser) analyseParameterPart(pattern string) (string, *r // find constraint part if exists in the parameter part and remove it if parameterEndPosition > 0 { parameterConstraintStart = findNextNonEscapedCharsetPosition(pattern[0:parameterEndPosition], parameterConstraintStartChars) - parameterConstraintEnd = findNextNonEscapedCharsetPosition(pattern[0:parameterEndPosition+1], parameterConstraintEndChars) + parameterConstraintEnd = findLastCharsetPosition(pattern[0:parameterEndPosition+1], parameterConstraintEndChars) } // cut params part @@ -262,12 +261,12 @@ func (routeParser *routeParser) analyseParameterPart(pattern string) (string, *r if hasConstraint := (parameterConstraintStart != -1 && parameterConstraintEnd != -1); hasConstraint { constraintString := pattern[parameterConstraintStart+1 : parameterConstraintEnd] - userconstraints := splitNonEscaped(constraintString, string(parameterConstraintSeparatorChars)) - constraints = make([]*Constraint, 0, len(userconstraints)) + userConstraints := splitNonEscaped(constraintString, string(parameterConstraintSeparatorChars)) + constraints = make([]*Constraint, 0, len(userConstraints)) - for _, c := range userconstraints { + for _, c := range userConstraints { start := findNextNonEscapedCharsetPosition(c, parameterConstraintDataStartChars) - end := findNextNonEscapedCharsetPosition(c, parameterConstraintDataEndChars) + end := findLastCharsetPosition(c, parameterConstraintDataEndChars) // Assign constraint if start != -1 && end != -1 { @@ -277,11 +276,13 @@ func (routeParser *routeParser) analyseParameterPart(pattern string) (string, *r } // remove escapes from data - if len(constraint.Data) == 1 { - constraint.Data[0] = RemoveEscapeChar(constraint.Data[0]) - } else if len(constraint.Data) == 2 { - constraint.Data[0] = RemoveEscapeChar(constraint.Data[0]) - constraint.Data[1] = RemoveEscapeChar(constraint.Data[1]) + if constraint.ID != regexConstraint { + if len(constraint.Data) == 1 { + constraint.Data[0] = RemoveEscapeChar(constraint.Data[0]) + } else if len(constraint.Data) == 2 { + constraint.Data[0] = RemoveEscapeChar(constraint.Data[0]) + constraint.Data[1] = RemoveEscapeChar(constraint.Data[1]) + } } // Precompile regex if has regex constraint @@ -346,6 +347,18 @@ func findNextCharsetPosition(search string, charset []byte) int { return nextPosition } +// findNextCharsetPosition search the last char position from the charset +func findLastCharsetPosition(search string, charset []byte) int { + lastPosition := -1 + for _, char := range charset { + if pos := strings.LastIndexByte(search, char); pos != -1 && (pos < lastPosition || lastPosition == -1) { + lastPosition = pos + } + } + + return lastPosition +} + // findNextCharsetPositionConstraint search the next char position from the charset // unlike findNextCharsetPosition, it takes care of constraint start-end chars to parse route pattern func findNextCharsetPositionConstraint(search string, charset []byte) int { @@ -363,7 +376,7 @@ func findNextCharsetPositionConstraint(search string, charset []byte) int { if char == paramConstraintEnd { constraintEnd = pos } - //fmt.Println(string(char)) + if pos != -1 && (pos < nextPosition || nextPosition == -1) { if pos > constraintStart && pos < constraintEnd { nextPosition = pos @@ -594,8 +607,6 @@ func (c *Constraint) CheckConstraint(param string) bool { } } - fmt.Print(c.Data) - // check constraints switch c.ID { case intConstraint: diff --git a/path_test.go b/path_test.go index 4ea2a1ec..ca02ea2b 100644 --- a/path_test.go +++ b/path_test.go @@ -520,12 +520,18 @@ func Test_Path_matchParams(t *testing.T) { {url: "/api/v1/8728382", params: []string{"8728382"}, match: false}, {url: "/api/v1/2005-11-01", params: []string{"2005-11-01"}, match: true}, }) - testCase("/api/v1/:param", []testparams{ + testCase("/api/v1/:param", []testparams{ {url: "/api/v1/ent", params: []string{"ent"}, match: false}, {url: "/api/v1/15", params: []string{"15"}, match: false}, {url: "/api/v1/peach", params: []string{"peach"}, match: true}, {url: "/api/v1/p34ch", params: []string{"p34ch"}, match: false}, }) + testCase("/api/v1/:param", []testparams{ + {url: "/api/v1/ent", params: []string{"ent"}, match: false}, + {url: "/api/v1/15", params: []string{"15"}, match: false}, + {url: "/api/v1/2022-08-27", params: []string{"2022-08-27"}, match: true}, + {url: "/api/v1/2022/08-27", params: []string{"p34ch"}, match: false}, + }) testCase("/api/v1/:param", []testparams{ {url: "/api/v1/entity", params: []string{"entity"}, match: false}, {url: "/api/v1/8728382", params: []string{"8728382"}, match: true}, @@ -739,12 +745,18 @@ func Benchmark_Path_matchParams(t *testing.B) { {url: "/api/v1/8728382", params: []string{"8728382"}, match: false}, {url: "/api/v1/2005-11-01", params: []string{"2005-11-01"}, match: true}, }) - benchCase("/api/v1/:param", []testparams{ + benchCase("/api/v1/:param", []testparams{ {url: "/api/v1/ent", params: []string{"ent"}, match: false}, {url: "/api/v1/15", params: []string{"15"}, match: false}, {url: "/api/v1/peach", params: []string{"peach"}, match: true}, {url: "/api/v1/p34ch", params: []string{"p34ch"}, match: false}, }) + benchCase("/api/v1/:param", []testparams{ + {url: "/api/v1/ent", params: []string{"ent"}, match: false}, + {url: "/api/v1/15", params: []string{"15"}, match: false}, + {url: "/api/v1/2022-08-27", params: []string{"2022-08-27"}, match: true}, + {url: "/api/v1/2022/08-27", params: []string{"p34ch"}, match: false}, + }) benchCase("/api/v1/:param", []testparams{ {url: "/api/v1/entity", params: []string{"entity"}, match: false}, {url: "/api/v1/8728382", params: []string{"8728382"}, match: true},