1
0
mirror of https://github.com/gofiber/fiber.git synced 2025-02-23 10:03:45 +00:00

Merge pull request #418 from Fenny/master

Fix partial wildcard in Static
This commit is contained in:
fenny 2020-05-27 17:04:33 -04:00 committed by GitHub
commit 1cd55804b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 142 additions and 55 deletions

2
app.go
View File

@ -26,7 +26,7 @@ import (
)
// Version of current package
const Version = "1.10.0"
const Version = "1.10.1"
// Map is a shortcut for map[string]interface{}, usefull for JSON returns
type Map map[string]interface{}

View File

@ -88,6 +88,33 @@ func Test_App_Use_Params_Group(t *testing.T) {
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_App_Chaining(t *testing.T) {
n := func(c *Ctx) {
c.Next()
}
app := New()
app.Use("/john", n, n, n, n, func(c *Ctx) {
c.Status(202)
})
req := httptest.NewRequest("POST", "/john", nil)
resp, err := app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 202, resp.StatusCode, "Status code")
app.Get("/test", n, n, n, n, func(c *Ctx) {
c.Status(203)
})
req = httptest.NewRequest("GET", "/test", nil)
resp, err = app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 203, resp.StatusCode, "Status code")
}
func Test_App_Order(t *testing.T) {
app := New()
@ -176,13 +203,66 @@ func Test_App_Shutdown(t *testing.T) {
_ = app.Shutdown()
}
func Test_App_Static(t *testing.T) {
// go test -run Test_App_Static
func Test_App_Static_Group(t *testing.T) {
app := New()
grp := app.Group("/v1")
grp := app.Group("/v1", func(c *Ctx) {
c.Set("Test-Header", "123")
c.Next()
})
grp.Static("/v2", ".github/auth_assign.yml")
app.Static("/*", ".github/FUNDING.yml")
grp.Static("/v2", "./.github/FUNDING.yml")
req := httptest.NewRequest("GET", "/v1/v2", nil)
resp, err := app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
utils.AssertEqual(t, "123", resp.Header.Get("Test-Header"))
grp = app.Group("/v2")
grp.Static("/v3*", "./.github/FUNDING.yml")
req = httptest.NewRequest("GET", "/v2/v3/john/doe", nil)
resp, err = app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
}
func Test_App_Static_Wildcard(t *testing.T) {
app := New()
app.Static("*", "./.github/FUNDING.yml")
req := httptest.NewRequest("GET", "/yesyes/john/doe", nil)
resp, err := app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
}
func Test_App_Static_Prefix_Wildcard(t *testing.T) {
app := New()
app.Static("/test/*", "./.github/FUNDING.yml")
req := httptest.NewRequest("GET", "/test/john/doe", nil)
resp, err := app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
}
func Test_App_Static_Prefix(t *testing.T) {
app := New()
app.Static("/john", "./.github")
req := httptest.NewRequest("GET", "/john/stale.yml", nil)
@ -190,24 +270,25 @@ func Test_App_Static(t *testing.T) {
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
req = httptest.NewRequest("GET", "/yesyes/john/doe", nil)
app.Static("/prefix", "./.github/workflows")
req = httptest.NewRequest("GET", "/prefix/test.yml", nil)
resp, err = app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
req = httptest.NewRequest("GET", "/john/stale.yml", nil)
resp, err = app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
req = httptest.NewRequest("GET", "/v1/v2", nil)
app.Static("/single", "./.github/workflows/test.yml")
req = httptest.NewRequest("GET", "/single", nil)
resp, err = app.Test(req)
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
}
func Test_App_Group(t *testing.T) {

22
ctx.go
View File

@ -34,8 +34,8 @@ import (
type Ctx struct {
app *App // Reference to *App
route *Route // Reference to *Route
index int // Index of the current handler in the stack
next bool // Bool to continue to the next handler
indexRoute int // Index of the current route
indexHandler int // Index of the current handler
method string // HTTP method
path string // Prettified HTTP path
pathOriginal string // Original HTTP path
@ -78,8 +78,9 @@ func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
ctx := app.pool.Get().(*Ctx)
// Set app reference
ctx.app = app
// Set stack index
ctx.index = -1
// Reset route and handler index
ctx.indexRoute = -1
ctx.indexHandler = 0
// Set paths
ctx.path = getString(fctx.URI().Path())
ctx.pathOriginal = ctx.path
@ -577,8 +578,17 @@ func (ctx *Ctx) Next(err ...error) {
if len(err) > 0 {
ctx.err = err[0]
}
ctx.next = true
ctx.app.next(ctx)
// Increment handler index
ctx.indexHandler++
// Did we executed all route handlers?
if ctx.indexHandler < len(ctx.route.Handlers) {
// Continue route stack
ctx.route.Handlers[ctx.indexHandler](ctx)
} else {
// Continue handler stack
ctx.app.next(ctx)
}
}
// OriginalURL contains the original request URL.

View File

@ -67,11 +67,11 @@ func (app *App) next(ctx *Ctx) bool {
// Get stack length
lenr := len(app.stack[method]) - 1
// Loop over the route stack starting from previous index
for ctx.index < lenr {
// Increment stack index
ctx.index++
for ctx.indexRoute < lenr {
// Increment route index
ctx.indexRoute++
// Get *Route
route := app.stack[method][ctx.index]
route := app.stack[method][ctx.indexRoute]
// Check if it matches the request path
match, values := route.match(ctx.path, ctx.pathOriginal)
// No match, next route
@ -81,17 +81,9 @@ func (app *App) next(ctx *Ctx) bool {
// Pass route reference and param values
ctx.route = route
ctx.values = values
// Loop trough all handlers
for i := range route.Handlers {
// Execute ctx handler
route.Handlers[i](ctx)
// Stop if c.Next() is not called
if !ctx.next {
break
}
// Reset next bool
ctx.next = false
}
// Execute first handler of route
ctx.indexHandler = 0
route.Handlers[0](ctx)
// Stop scanning the stack
return true
}
@ -191,6 +183,10 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) *Route {
}
func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
// For security we want to restrict to the current work directory.
if len(root) == 0 {
root = "."
}
// Cannot have an empty prefix
if prefix == "" {
prefix = "/"
@ -199,31 +195,26 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
if prefix[0] != '/' {
prefix = "/" + prefix
}
// Match anything
var wildcard = false
if prefix == "*" || prefix == "/*" {
wildcard = true
prefix = "/"
}
// in case sensitive routing, all to lowercase
if !app.Settings.CaseSensitive {
prefix = utils.ToLower(prefix)
}
// For security we want to restrict to the current work directory.
if len(root) == 0 {
root = "."
}
// Strip trailing slashes from the root path
if len(root) > 0 && root[len(root)-1] == '/' {
root = root[:len(root)-1]
}
// isSlash ?
// Is prefix a direct wildcard?
var isStar = prefix == "/*"
// Is prefix a root slash?
var isRoot = prefix == "/"
// Is prefix a partial wildcard?
if strings.Contains(prefix, "*") {
wildcard = true
// /john* -> /john
isStar = true
prefix = strings.Split(prefix, "*")[0]
// Fix this later
}
var stripper = len(prefix) - 1
prefixLen := len(prefix)
// Fileserver settings
fs := &fasthttp.FS{
Root: root,
@ -233,7 +224,17 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
CompressedFileSuffix: ".fiber.gz",
CacheDuration: 10 * time.Second,
IndexNames: []string{"index.html"},
PathRewrite: fasthttp.NewPathPrefixStripper(stripper),
PathRewrite: func(ctx *fasthttp.RequestCtx) []byte {
path := ctx.Path()
if len(path) >= prefixLen {
if isStar && getString(path[0:prefixLen]) == prefix {
path = path[0:0]
} else {
path = path[prefixLen:]
}
}
return append(path, '/')
},
PathNotFound: func(ctx *fasthttp.RequestCtx) {
ctx.Response.SetStatusCode(404)
},
@ -249,10 +250,6 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
}
fileHandler := fs.NewRequestHandler()
handler := func(c *Ctx) {
// Do stuff
if wildcard {
c.Fasthttp.Request.SetRequestURI(prefix)
}
// Serve file
fileHandler(c.Fasthttp)
// Return request if found and not forbidden
@ -283,7 +280,6 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
app.addRoute(MethodHead, route)
return route
}
func (app *App) addRoute(method string, route *Route) {
// Get unique HTTP method indentifier
m := methodINT[method]

View File

@ -254,11 +254,11 @@ func Benchmark_Router_Next(b *testing.B) {
defer app.ReleaseCtx(c)
for n := 0; n < b.N; n++ {
c.index = -1
c.indexRoute = -1
res = app.next(c)
}
utils.AssertEqual(b, true, res)
utils.AssertEqual(b, 31, c.index)
utils.AssertEqual(b, 31, c.indexRoute)
}
// go test -v ./... -run=^$ -bench=Benchmark_Route_Match -benchmem -count=4