1
0
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:
ReneWerner87 2020-08-10 09:50:53 +02:00
parent cff454dfc2
commit 67caca823b
3 changed files with 98 additions and 21 deletions

View File

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

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

View File

@ -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()