Skip to content

Commit 1cd5580

Browse files
authored
Merge pull request #418 from Fenny/master
Fix partial wildcard in Static
2 parents f2c027e + 30c215c commit 1cd5580

File tree

5 files changed

+139
-52
lines changed

5 files changed

+139
-52
lines changed

app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
)
2727

2828
// Version of current package
29-
const Version = "1.10.0"
29+
const Version = "1.10.1"
3030

3131
// Map is a shortcut for map[string]interface{}, usefull for JSON returns
3232
type Map map[string]interface{}

app_test.go

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,33 @@ func Test_App_Use_Params_Group(t *testing.T) {
8888
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
8989
}
9090

91+
func Test_App_Chaining(t *testing.T) {
92+
n := func(c *Ctx) {
93+
c.Next()
94+
}
95+
app := New()
96+
app.Use("/john", n, n, n, n, func(c *Ctx) {
97+
c.Status(202)
98+
})
99+
100+
req := httptest.NewRequest("POST", "/john", nil)
101+
102+
resp, err := app.Test(req)
103+
utils.AssertEqual(t, nil, err, "app.Test(req)")
104+
utils.AssertEqual(t, 202, resp.StatusCode, "Status code")
105+
106+
app.Get("/test", n, n, n, n, func(c *Ctx) {
107+
c.Status(203)
108+
})
109+
110+
req = httptest.NewRequest("GET", "/test", nil)
111+
112+
resp, err = app.Test(req)
113+
utils.AssertEqual(t, nil, err, "app.Test(req)")
114+
utils.AssertEqual(t, 203, resp.StatusCode, "Status code")
115+
116+
}
117+
91118
func Test_App_Order(t *testing.T) {
92119
app := New()
93120

@@ -176,38 +203,92 @@ func Test_App_Shutdown(t *testing.T) {
176203
_ = app.Shutdown()
177204
}
178205

179-
func Test_App_Static(t *testing.T) {
206+
// go test -run Test_App_Static
207+
func Test_App_Static_Group(t *testing.T) {
180208
app := New()
181209

182-
grp := app.Group("/v1")
210+
grp := app.Group("/v1", func(c *Ctx) {
211+
c.Set("Test-Header", "123")
212+
c.Next()
213+
})
183214

184-
grp.Static("/v2", ".github/auth_assign.yml")
185-
app.Static("/*", ".github/FUNDING.yml")
186-
app.Static("/john", "./.github")
215+
grp.Static("/v2", "./.github/FUNDING.yml")
187216

188-
req := httptest.NewRequest("GET", "/john/stale.yml", nil)
217+
req := httptest.NewRequest("GET", "/v1/v2", nil)
189218
resp, err := app.Test(req)
190219
utils.AssertEqual(t, nil, err, "app.Test(req)")
191220
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
192221
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
222+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
223+
utils.AssertEqual(t, "123", resp.Header.Get("Test-Header"))
193224

194-
req = httptest.NewRequest("GET", "/yesyes/john/doe", nil)
225+
grp = app.Group("/v2")
226+
grp.Static("/v3*", "./.github/FUNDING.yml")
227+
228+
req = httptest.NewRequest("GET", "/v2/v3/john/doe", nil)
195229
resp, err = app.Test(req)
196230
utils.AssertEqual(t, nil, err, "app.Test(req)")
197231
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
198232
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
233+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
234+
235+
}
236+
237+
func Test_App_Static_Wildcard(t *testing.T) {
238+
app := New()
239+
240+
app.Static("*", "./.github/FUNDING.yml")
241+
242+
req := httptest.NewRequest("GET", "/yesyes/john/doe", nil)
243+
resp, err := app.Test(req)
244+
utils.AssertEqual(t, nil, err, "app.Test(req)")
245+
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
246+
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
247+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
248+
249+
}
199250

200-
req = httptest.NewRequest("GET", "/john/stale.yml", nil)
251+
func Test_App_Static_Prefix_Wildcard(t *testing.T) {
252+
app := New()
253+
254+
app.Static("/test/*", "./.github/FUNDING.yml")
255+
256+
req := httptest.NewRequest("GET", "/test/john/doe", nil)
257+
resp, err := app.Test(req)
258+
utils.AssertEqual(t, nil, err, "app.Test(req)")
259+
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
260+
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
261+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
262+
}
263+
264+
func Test_App_Static_Prefix(t *testing.T) {
265+
app := New()
266+
app.Static("/john", "./.github")
267+
268+
req := httptest.NewRequest("GET", "/john/stale.yml", nil)
269+
resp, err := app.Test(req)
270+
utils.AssertEqual(t, nil, err, "app.Test(req)")
271+
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
272+
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
273+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
274+
275+
app.Static("/prefix", "./.github/workflows")
276+
277+
req = httptest.NewRequest("GET", "/prefix/test.yml", nil)
201278
resp, err = app.Test(req)
202279
utils.AssertEqual(t, nil, err, "app.Test(req)")
203280
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
204281
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
282+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
283+
284+
app.Static("/single", "./.github/workflows/test.yml")
205285

206-
req = httptest.NewRequest("GET", "/v1/v2", nil)
286+
req = httptest.NewRequest("GET", "/single", nil)
207287
resp, err = app.Test(req)
208288
utils.AssertEqual(t, nil, err, "app.Test(req)")
209289
utils.AssertEqual(t, 200, resp.StatusCode, "Status code")
210290
utils.AssertEqual(t, false, resp.Header.Get("Content-Length") == "")
291+
utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type"))
211292
}
212293

213294
func Test_App_Group(t *testing.T) {

ctx.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ import (
3434
type Ctx struct {
3535
app *App // Reference to *App
3636
route *Route // Reference to *Route
37-
index int // Index of the current handler in the stack
38-
next bool // Bool to continue to the next handler
37+
indexRoute int // Index of the current route
38+
indexHandler int // Index of the current handler
3939
method string // HTTP method
4040
path string // Prettified HTTP path
4141
pathOriginal string // Original HTTP path
@@ -78,8 +78,9 @@ func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
7878
ctx := app.pool.Get().(*Ctx)
7979
// Set app reference
8080
ctx.app = app
81-
// Set stack index
82-
ctx.index = -1
81+
// Reset route and handler index
82+
ctx.indexRoute = -1
83+
ctx.indexHandler = 0
8384
// Set paths
8485
ctx.path = getString(fctx.URI().Path())
8586
ctx.pathOriginal = ctx.path
@@ -577,8 +578,17 @@ func (ctx *Ctx) Next(err ...error) {
577578
if len(err) > 0 {
578579
ctx.err = err[0]
579580
}
580-
ctx.next = true
581-
ctx.app.next(ctx)
581+
582+
// Increment handler index
583+
ctx.indexHandler++
584+
// Did we executed all route handlers?
585+
if ctx.indexHandler < len(ctx.route.Handlers) {
586+
// Continue route stack
587+
ctx.route.Handlers[ctx.indexHandler](ctx)
588+
} else {
589+
// Continue handler stack
590+
ctx.app.next(ctx)
591+
}
582592
}
583593

584594
// OriginalURL contains the original request URL.

router.go

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ func (app *App) next(ctx *Ctx) bool {
6767
// Get stack length
6868
lenr := len(app.stack[method]) - 1
6969
// Loop over the route stack starting from previous index
70-
for ctx.index < lenr {
71-
// Increment stack index
72-
ctx.index++
70+
for ctx.indexRoute < lenr {
71+
// Increment route index
72+
ctx.indexRoute++
7373
// Get *Route
74-
route := app.stack[method][ctx.index]
74+
route := app.stack[method][ctx.indexRoute]
7575
// Check if it matches the request path
7676
match, values := route.match(ctx.path, ctx.pathOriginal)
7777
// No match, next route
@@ -81,17 +81,9 @@ func (app *App) next(ctx *Ctx) bool {
8181
// Pass route reference and param values
8282
ctx.route = route
8383
ctx.values = values
84-
// Loop trough all handlers
85-
for i := range route.Handlers {
86-
// Execute ctx handler
87-
route.Handlers[i](ctx)
88-
// Stop if c.Next() is not called
89-
if !ctx.next {
90-
break
91-
}
92-
// Reset next bool
93-
ctx.next = false
94-
}
84+
// Execute first handler of route
85+
ctx.indexHandler = 0
86+
route.Handlers[0](ctx)
9587
// Stop scanning the stack
9688
return true
9789
}
@@ -191,6 +183,10 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) *Route {
191183
}
192184

193185
func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
186+
// For security we want to restrict to the current work directory.
187+
if len(root) == 0 {
188+
root = "."
189+
}
194190
// Cannot have an empty prefix
195191
if prefix == "" {
196192
prefix = "/"
@@ -199,31 +195,26 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
199195
if prefix[0] != '/' {
200196
prefix = "/" + prefix
201197
}
202-
// Match anything
203-
var wildcard = false
204-
if prefix == "*" || prefix == "/*" {
205-
wildcard = true
206-
prefix = "/"
207-
}
208198
// in case sensitive routing, all to lowercase
209199
if !app.Settings.CaseSensitive {
210200
prefix = utils.ToLower(prefix)
211201
}
212-
// For security we want to restrict to the current work directory.
213-
if len(root) == 0 {
214-
root = "."
215-
}
216202
// Strip trailing slashes from the root path
217203
if len(root) > 0 && root[len(root)-1] == '/' {
218204
root = root[:len(root)-1]
219205
}
220-
// isSlash ?
206+
// Is prefix a direct wildcard?
207+
var isStar = prefix == "/*"
208+
// Is prefix a root slash?
221209
var isRoot = prefix == "/"
210+
// Is prefix a partial wildcard?
222211
if strings.Contains(prefix, "*") {
223-
wildcard = true
212+
// /john* -> /john
213+
isStar = true
224214
prefix = strings.Split(prefix, "*")[0]
215+
// Fix this later
225216
}
226-
var stripper = len(prefix) - 1
217+
prefixLen := len(prefix)
227218
// Fileserver settings
228219
fs := &fasthttp.FS{
229220
Root: root,
@@ -233,7 +224,17 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
233224
CompressedFileSuffix: ".fiber.gz",
234225
CacheDuration: 10 * time.Second,
235226
IndexNames: []string{"index.html"},
236-
PathRewrite: fasthttp.NewPathPrefixStripper(stripper),
227+
PathRewrite: func(ctx *fasthttp.RequestCtx) []byte {
228+
path := ctx.Path()
229+
if len(path) >= prefixLen {
230+
if isStar && getString(path[0:prefixLen]) == prefix {
231+
path = path[0:0]
232+
} else {
233+
path = path[prefixLen:]
234+
}
235+
}
236+
return append(path, '/')
237+
},
237238
PathNotFound: func(ctx *fasthttp.RequestCtx) {
238239
ctx.Response.SetStatusCode(404)
239240
},
@@ -249,10 +250,6 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
249250
}
250251
fileHandler := fs.NewRequestHandler()
251252
handler := func(c *Ctx) {
252-
// Do stuff
253-
if wildcard {
254-
c.Fasthttp.Request.SetRequestURI(prefix)
255-
}
256253
// Serve file
257254
fileHandler(c.Fasthttp)
258255
// Return request if found and not forbidden
@@ -283,7 +280,6 @@ func (app *App) registerStatic(prefix, root string, config ...Static) *Route {
283280
app.addRoute(MethodHead, route)
284281
return route
285282
}
286-
287283
func (app *App) addRoute(method string, route *Route) {
288284
// Get unique HTTP method indentifier
289285
m := methodINT[method]

router_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,11 @@ func Benchmark_Router_Next(b *testing.B) {
254254
defer app.ReleaseCtx(c)
255255

256256
for n := 0; n < b.N; n++ {
257-
c.index = -1
257+
c.indexRoute = -1
258258
res = app.next(c)
259259
}
260260
utils.AssertEqual(b, true, res)
261-
utils.AssertEqual(b, 31, c.index)
261+
utils.AssertEqual(b, 31, c.indexRoute)
262262
}
263263

264264
// go test -v ./... -run=^$ -bench=Benchmark_Route_Match -benchmem -count=4

0 commit comments

Comments
 (0)