mirror of https://github.com/gofiber/fiber.git
parent
383d037a95
commit
b51def0bb8
22
app_test.go
22
app_test.go
|
@ -314,6 +314,28 @@ func Test_App_Use_Params(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func Test_App_Use_UnescapedPath(t *testing.T) {
|
||||
app := New(Config{UnescapePath: true, CaseSensitive: true})
|
||||
|
||||
app.Use("/cRéeR/:param", func(c *Ctx) error {
|
||||
return c.SendString(c.Params("param"))
|
||||
})
|
||||
|
||||
resp, err := app.Test(httptest.NewRequest(MethodGet, "/cR%C3%A9eR/%D9%85%D8%AD%D9%85%D8%AF", nil))
|
||||
utils.AssertEqual(t, nil, err, "app.Test(req)")
|
||||
utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
utils.AssertEqual(t, nil, err, "app.Test(req)")
|
||||
// check the param result
|
||||
utils.AssertEqual(t, "محمد", getString(body))
|
||||
|
||||
// with lowercase letters
|
||||
resp, err = app.Test(httptest.NewRequest(MethodGet, "/cr%C3%A9er/%D9%85%D8%AD%D9%85%D8%AF", nil))
|
||||
utils.AssertEqual(t, nil, err, "app.Test(req)")
|
||||
utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
|
||||
}
|
||||
|
||||
func Test_App_Add_Method_Test(t *testing.T) {
|
||||
app := New()
|
||||
defer func() {
|
||||
|
|
73
ctx.go
73
ctx.go
|
@ -33,20 +33,22 @@ const maxParams = 30
|
|||
// Ctx represents the Context which hold the HTTP request and response.
|
||||
// It has methods for the request query string, parameters, body, HTTP headers and so on.
|
||||
type Ctx struct {
|
||||
app *App // Reference to *App
|
||||
route *Route // Reference to *Route
|
||||
indexRoute int // Index of the current route
|
||||
indexHandler int // Index of the current handler
|
||||
method string // HTTP method
|
||||
methodINT int // HTTP method INT equivalent
|
||||
baseURI string // HTTP base uri
|
||||
path string // Prettified HTTP path -> string copy from pathBuffer
|
||||
pathBuffer []byte // Prettified HTTP path buffer
|
||||
treePath string // Path for the search in the tree
|
||||
pathOriginal string // Original HTTP path
|
||||
values [maxParams]string // Route parameter values
|
||||
fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx
|
||||
matched bool // Non use route matched
|
||||
app *App // Reference to *App
|
||||
route *Route // Reference to *Route
|
||||
indexRoute int // Index of the current route
|
||||
indexHandler int // Index of the current handler
|
||||
method string // HTTP method
|
||||
methodINT int // HTTP method INT equivalent
|
||||
baseURI string // HTTP base uri
|
||||
path string // Prettified HTTP path for the user -> string copy from pathBuffer
|
||||
pathBuffer []byte // HTTP path buffer
|
||||
detectionPath string // Route detection path -> string copy from pathBuffer
|
||||
detectionPathBuffer []byte // HTTP path detectionPath
|
||||
treePath string // Path for the search in the tree
|
||||
pathOriginal string // Original HTTP path
|
||||
values [maxParams]string // Route parameter values
|
||||
fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx
|
||||
matched bool // Non use route matched
|
||||
}
|
||||
|
||||
// Range data for c.Range
|
||||
|
@ -88,7 +90,6 @@ func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
|||
// Reset matched flag
|
||||
c.matched = false
|
||||
// Set paths
|
||||
c.pathBuffer = append(c.pathBuffer[0:0], fctx.URI().PathOriginal()...)
|
||||
c.pathOriginal = getString(fctx.URI().PathOriginal())
|
||||
// Set method
|
||||
c.method = getString(fctx.Request.Header.Method())
|
||||
|
@ -98,7 +99,7 @@ func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
|||
// reset base uri
|
||||
c.baseURI = ""
|
||||
// Prettify path
|
||||
c.prettifyPath()
|
||||
c.configDependentPaths()
|
||||
return c
|
||||
}
|
||||
|
||||
|
@ -674,15 +675,12 @@ func (c *Ctx) Params(key string, defaultValue ...string) string {
|
|||
func (c *Ctx) Path(override ...string) string {
|
||||
if len(override) != 0 && c.path != override[0] {
|
||||
// Set new path to context
|
||||
c.pathBuffer = append(c.pathBuffer[0:0], override[0]...)
|
||||
c.pathOriginal = override[0]
|
||||
// c.path = override[0]
|
||||
// c.pathOriginal = c.path
|
||||
|
||||
// Set new path to request context
|
||||
c.fasthttp.Request.URI().SetPath(c.pathOriginal)
|
||||
// Prettify path
|
||||
c.prettifyPath()
|
||||
c.configDependentPaths()
|
||||
}
|
||||
return c.pathOriginal
|
||||
}
|
||||
|
@ -1105,24 +1103,33 @@ func (c *Ctx) XHR() bool {
|
|||
return utils.EqualFoldBytes(utils.UnsafeBytes(c.Get(HeaderXRequestedWith)), []byte("xmlhttprequest"))
|
||||
}
|
||||
|
||||
// prettifyPath ...
|
||||
func (c *Ctx) prettifyPath() {
|
||||
// If UnescapePath enabled, we decode the path
|
||||
// configDependentPaths set paths for route recognition and prepared paths for the user,
|
||||
// here the features for caseSensitive, decoded paths, strict paths are evaluated
|
||||
func (c *Ctx) configDependentPaths() {
|
||||
c.pathBuffer = append(c.pathBuffer[0:0], c.pathOriginal...)
|
||||
// If UnescapePath enabled, we decode the path and save it for the framework user
|
||||
if c.app.config.UnescapePath {
|
||||
c.pathBuffer = fasthttp.AppendUnquotedArg(c.pathBuffer[:0], c.pathBuffer)
|
||||
}
|
||||
// If CaseSensitive is disabled, we lowercase the original path
|
||||
if !c.app.config.CaseSensitive {
|
||||
c.pathBuffer = utils.ToLowerBytes(c.pathBuffer)
|
||||
}
|
||||
// If StrictRouting is disabled, we strip all trailing slashes
|
||||
if !c.app.config.StrictRouting && len(c.pathBuffer) > 1 && c.pathBuffer[len(c.pathBuffer)-1] == '/' {
|
||||
c.pathBuffer = utils.TrimRightBytes(c.pathBuffer, '/')
|
||||
}
|
||||
c.path = getString(c.pathBuffer)
|
||||
|
||||
// another path is specified which is for routing recognition only
|
||||
// use the path that was changed by the previous configuration flags
|
||||
c.detectionPathBuffer = append(c.detectionPathBuffer[0:0], c.pathBuffer...)
|
||||
// If CaseSensitive is disabled, we lowercase the original path
|
||||
if !c.app.config.CaseSensitive {
|
||||
c.detectionPathBuffer = utils.ToLowerBytes(c.detectionPathBuffer)
|
||||
}
|
||||
// If StrictRouting is disabled, we strip all trailing slashes
|
||||
if !c.app.config.StrictRouting && len(c.detectionPathBuffer) > 1 && c.detectionPathBuffer[len(c.detectionPathBuffer)-1] == '/' {
|
||||
c.detectionPathBuffer = utils.TrimRightBytes(c.detectionPathBuffer, '/')
|
||||
}
|
||||
c.detectionPath = getString(c.detectionPathBuffer)
|
||||
|
||||
// Define the path for dividing routes into areas for fast tree detection, so that fewer routes need to be traversed,
|
||||
// since the first three characters area select a list of routes
|
||||
c.treePath = c.treePath[0:0]
|
||||
if len(c.path) >= 3 {
|
||||
c.treePath = c.path[:3]
|
||||
if len(c.detectionPath) >= 3 {
|
||||
c.treePath = c.detectionPath[:3]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ func methodExist(ctx *Ctx) (exist bool) {
|
|||
continue
|
||||
}
|
||||
// Check if it matches the request path
|
||||
match := route.match(ctx.path, ctx.pathOriginal, &ctx.values)
|
||||
match := route.match(ctx.detectionPath, ctx.path, &ctx.values)
|
||||
// No match, next route
|
||||
if match {
|
||||
// We matched
|
||||
|
|
16
path.go
16
path.go
|
@ -227,37 +227,37 @@ func findNextCharsetPosition(search string, charset []byte) int {
|
|||
}
|
||||
|
||||
// getMatch parses the passed url and tries to match it against the route segments and determine the parameter positions
|
||||
func (routeParser *routeParser) getMatch(s, original string, params *[maxParams]string, partialCheck bool) bool {
|
||||
func (routeParser *routeParser) getMatch(detectionPath, path string, params *[maxParams]string, partialCheck bool) bool {
|
||||
var i, paramsIterator, partLen int
|
||||
for _, segment := range routeParser.segs {
|
||||
partLen = len(s)
|
||||
partLen = len(detectionPath)
|
||||
// check const segment
|
||||
if !segment.IsParam {
|
||||
i = segment.Length
|
||||
// is optional part or the const part must match with the given string
|
||||
// check if the end of the segment is a optional slash
|
||||
if segment.HasOptionalSlash && partLen == i-1 && s == segment.Const[:i-1] {
|
||||
if segment.HasOptionalSlash && partLen == i-1 && detectionPath == segment.Const[:i-1] {
|
||||
i--
|
||||
} else if !(i <= partLen && s[:i] == segment.Const) {
|
||||
} else if !(i <= partLen && detectionPath[:i] == segment.Const) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// determine parameter length
|
||||
i = findParamLen(s, segment)
|
||||
i = findParamLen(detectionPath, segment)
|
||||
if !segment.IsOptional && i == 0 {
|
||||
return false
|
||||
}
|
||||
// take over the params positions
|
||||
params[paramsIterator] = original[:i]
|
||||
params[paramsIterator] = path[:i]
|
||||
paramsIterator++
|
||||
}
|
||||
|
||||
// reduce founded part from the string
|
||||
if partLen > 0 {
|
||||
s, original = s[i:], original[i:]
|
||||
detectionPath, path = detectionPath[i:], path[i:]
|
||||
}
|
||||
}
|
||||
if len(s) != 0 && !partialCheck {
|
||||
if len(detectionPath) != 0 && !partialCheck {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
26
router.go
26
router.go
|
@ -55,14 +55,14 @@ type Route struct {
|
|||
Handlers []Handler `json:"-"` // Ctx handlers
|
||||
}
|
||||
|
||||
func (r *Route) match(path, original string, params *[maxParams]string) (match bool) {
|
||||
// root path check
|
||||
if r.root && path == "/" {
|
||||
func (r *Route) match(detectionPath, path string, params *[maxParams]string) (match bool) {
|
||||
// root detectionPath check
|
||||
if r.root && detectionPath == "/" {
|
||||
return true
|
||||
// '*' wildcard matches any path
|
||||
// '*' wildcard matches any detectionPath
|
||||
} else if r.star {
|
||||
if len(original) > 1 {
|
||||
params[0] = original[1:]
|
||||
if len(path) > 1 {
|
||||
params[0] = path[1:]
|
||||
} else {
|
||||
params[0] = ""
|
||||
}
|
||||
|
@ -71,19 +71,19 @@ func (r *Route) match(path, original string, params *[maxParams]string) (match b
|
|||
// Does this route have parameters
|
||||
if len(r.Params) > 0 {
|
||||
// Match params
|
||||
if match := r.routeParser.getMatch(path, original, params, r.use); match {
|
||||
// Get params from the original path
|
||||
if match := r.routeParser.getMatch(detectionPath, path, params, r.use); match {
|
||||
// Get params from the path detectionPath
|
||||
return match
|
||||
}
|
||||
}
|
||||
// Is this route a Middleware?
|
||||
if r.use {
|
||||
// Single slash will match or path prefix
|
||||
if r.root || strings.HasPrefix(path, r.path) {
|
||||
// Single slash will match or detectionPath prefix
|
||||
if r.root || strings.HasPrefix(detectionPath, r.path) {
|
||||
return true
|
||||
}
|
||||
// Check for a simple path match
|
||||
} else if len(r.path) == len(path) && r.path == path {
|
||||
// Check for a simple detectionPath match
|
||||
} else if len(r.path) == len(detectionPath) && r.path == detectionPath {
|
||||
return true
|
||||
}
|
||||
// No match
|
||||
|
@ -107,7 +107,7 @@ func (app *App) next(c *Ctx) (match bool, err error) {
|
|||
route := tree[c.indexRoute]
|
||||
|
||||
// Check if it matches the request path
|
||||
match = route.match(c.path, c.pathOriginal, &c.values)
|
||||
match = route.match(c.detectionPath, c.path, &c.values)
|
||||
|
||||
// No match, next route
|
||||
if !match {
|
||||
|
|
Loading…
Reference in New Issue