mirror of
https://github.com/gofiber/fiber.git
synced 2025-02-20 22:12:56 +00:00
🚀 improve routing behavior
This commit is contained in:
parent
cff454dfc2
commit
67caca823b
@ -916,6 +916,7 @@ func Test_Ctx_Params(t *testing.T) {
|
||||
app.Get("/test3/*/blafasel/*", func(c *Ctx) {
|
||||
utils.AssertEqual(t, "1111", c.Params("*1"))
|
||||
utils.AssertEqual(t, "2222", c.Params("*2"))
|
||||
utils.AssertEqual(t, "1111", c.Params("*"))
|
||||
})
|
||||
app.Get("/test4/:optional?", func(c *Ctx) {
|
||||
utils.AssertEqual(t, "", c.Params("optional"))
|
||||
|
31
path.go
31
path.go
@ -30,7 +30,6 @@ type routeSegment struct {
|
||||
ParamName string
|
||||
ComparePart string // search part to find the end of the parameter
|
||||
PartCount int // how often is the search part contained in the non-param segments? -> necessary for greedy search
|
||||
IsWildcard bool
|
||||
IsGreedy bool
|
||||
IsOptional bool
|
||||
IsLast bool
|
||||
@ -48,7 +47,6 @@ const (
|
||||
var (
|
||||
// list of possible parameter and segment delimiter
|
||||
// slash has a special role, unlike the other parameters it must not be interpreted as a parameter
|
||||
// TODO '(' ')' delimiters for regex patterns
|
||||
routeDelimiter = []byte{slashDelimiter, '-', '.'}
|
||||
// list of chars for the parameter recognising
|
||||
parameterStartChars = []byte{wildcardParam, plusParam, paramStarterChar}
|
||||
@ -217,9 +215,8 @@ func (routeParser *routeParser) getMatch(s string, partialCheck bool) ([][2]int,
|
||||
var i, paramsIterator, partLen, paramStart int
|
||||
for index, segment := range routeParser.segs {
|
||||
partLen = len(s)
|
||||
// check parameter
|
||||
// check const segment
|
||||
if !segment.IsParam {
|
||||
// check const segment
|
||||
optionalPart := false
|
||||
i = len(segment.Const)
|
||||
// check if the end of the segment is a optional slash and then if the segement is optional or the last one
|
||||
@ -284,29 +281,21 @@ func findParamLen(s string, segments []routeSegment, currIndex int) int {
|
||||
}
|
||||
|
||||
compareSeg := segments[currIndex+1]
|
||||
// check if parameter segments are directly after each other
|
||||
if compareSeg.IsParam {
|
||||
// and if one of them is greedy
|
||||
if !segments[currIndex].IsGreedy && !compareSeg.IsGreedy && len(s) > 0 {
|
||||
// in case the next parameter or the current parameter is not a wildcard its not greedy, we only want one character
|
||||
return 1
|
||||
}
|
||||
// check if parameter segments are directly after each other and if one of them is greedy
|
||||
if compareSeg.IsParam && !segments[currIndex].IsGreedy && !compareSeg.IsGreedy && len(s) > 0 {
|
||||
// in case the next parameter or the current parameter is not a wildcard its not greedy, we only want one character
|
||||
return 1
|
||||
}
|
||||
|
||||
return findParamLenUntilNextConstSeg(s, segments[currIndex])
|
||||
}
|
||||
|
||||
// findParamLenUntilNextConstSeg Search the parameters until the next constant part
|
||||
func findParamLenUntilNextConstSeg(s string, segment routeSegment) int {
|
||||
// Search the parameters until the next constant part
|
||||
// special logic for greedy params
|
||||
if segment.IsGreedy {
|
||||
searchCount := strings.Count(s, segment.ComparePart)
|
||||
if segments[currIndex].IsGreedy {
|
||||
searchCount := strings.Count(s, segments[currIndex].ComparePart)
|
||||
if searchCount > 1 {
|
||||
return findGreedyParamLen(s, searchCount, segment)
|
||||
return findGreedyParamLen(s, searchCount, segments[currIndex])
|
||||
}
|
||||
}
|
||||
|
||||
if constPosition := strings.Index(s, segment.ComparePart); constPosition != -1 {
|
||||
if constPosition := strings.Index(s, segments[currIndex].ComparePart); constPosition != -1 {
|
||||
return constPosition
|
||||
}
|
||||
|
||||
|
87
path_test.go
87
path_test.go
@ -12,6 +12,93 @@ import (
|
||||
utils "github.com/gofiber/utils"
|
||||
)
|
||||
|
||||
// go test -race -run Test_Path_parseRoute
|
||||
func Test_Path_parseRoute(t *testing.T) {
|
||||
var rp routeParser
|
||||
|
||||
rp = parseRoute("/shop/product/::filter/color::color/size::size")
|
||||
utils.AssertEqual(t, routeParser{
|
||||
segs: []routeSegment{
|
||||
{Const: "/shop/product/:"},
|
||||
{IsParam: true, ParamName: "filter", ComparePart: "/color:", PartCount: 1},
|
||||
{Const: "/color:"},
|
||||
{IsParam: true, ParamName: "color", ComparePart: "/size:", PartCount: 1},
|
||||
{Const: "/size:"},
|
||||
{IsParam: true, ParamName: "size", IsLast: true},
|
||||
},
|
||||
params: []string{"filter", "color", "size"},
|
||||
wildCardCount: 0,
|
||||
plusCount: 0,
|
||||
}, rp)
|
||||
|
||||
rp = parseRoute("/api/v1/:param/abc/*")
|
||||
utils.AssertEqual(t, routeParser{
|
||||
segs: []routeSegment{
|
||||
{Const: "/api/v1/"},
|
||||
{IsParam: true, ParamName: "param", ComparePart: "/abc", PartCount: 1},
|
||||
{Const: "/abc/"},
|
||||
{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, IsLast: true},
|
||||
},
|
||||
params: []string{"param", "*1"},
|
||||
wildCardCount: 1,
|
||||
plusCount: 0,
|
||||
}, rp)
|
||||
|
||||
rp = parseRoute("/api/*/:param/:param2")
|
||||
utils.AssertEqual(t, routeParser{
|
||||
segs: []routeSegment{
|
||||
{Const: "/api/"},
|
||||
{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, ComparePart: "/", PartCount: 2},
|
||||
{Const: "/"},
|
||||
{IsParam: true, ParamName: "param", ComparePart: "/", PartCount: 1},
|
||||
{Const: "/"},
|
||||
{IsParam: true, ParamName: "param2", IsLast: true},
|
||||
},
|
||||
params: []string{"*1", "param", "param2"},
|
||||
wildCardCount: 1,
|
||||
plusCount: 0,
|
||||
}, rp)
|
||||
|
||||
rp = parseRoute("/test:optional?:optional2?")
|
||||
utils.AssertEqual(t, routeParser{
|
||||
segs: []routeSegment{
|
||||
{Const: "/test"},
|
||||
{IsParam: true, ParamName: "optional", IsOptional: true},
|
||||
{IsParam: true, ParamName: "optional2", IsOptional: true, IsLast: true},
|
||||
},
|
||||
params: []string{"optional", "optional2"},
|
||||
wildCardCount: 0,
|
||||
plusCount: 0,
|
||||
}, rp)
|
||||
|
||||
rp = parseRoute("/config/+.json")
|
||||
utils.AssertEqual(t, routeParser{
|
||||
segs: []routeSegment{
|
||||
{Const: "/config/"},
|
||||
{IsParam: true, ParamName: "+1", IsGreedy: true, IsOptional: false, ComparePart: ".json", PartCount: 0},
|
||||
{Const: ".json", IsLast: true},
|
||||
},
|
||||
params: []string{"+1"},
|
||||
wildCardCount: 0,
|
||||
plusCount: 1,
|
||||
}, rp)
|
||||
|
||||
rp = parseRoute("/api/:day.:month?.:year?")
|
||||
utils.AssertEqual(t, routeParser{
|
||||
segs: []routeSegment{
|
||||
{Const: "/api/"},
|
||||
{IsParam: true, ParamName: "day", IsOptional: false, ComparePart: ".", PartCount: 2},
|
||||
{Const: "."},
|
||||
{IsParam: true, ParamName: "month", IsOptional: true, ComparePart: ".", PartCount: 1},
|
||||
{Const: "."},
|
||||
{IsParam: true, ParamName: "year", IsOptional: true, IsLast: true},
|
||||
},
|
||||
params: []string{"day", "month", "year"},
|
||||
wildCardCount: 0,
|
||||
plusCount: 0,
|
||||
}, rp)
|
||||
}
|
||||
|
||||
// go test -race -run Test_Path_matchParams
|
||||
func Test_Path_matchParams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
Loading…
x
Reference in New Issue
Block a user