diff --git a/beego.go b/beego.go index 32c1ee47..a58df00a 100644 --- a/beego.go +++ b/beego.go @@ -318,9 +318,10 @@ func DelStaticPath(url string) *App { // InsertFilter adds a FilterFunc with pattern condition and action constant. // The pos means action constant including -// beego.BeforeRouter, beego.AfterStatic, beego.BeforeExec, beego.AfterExec and beego.FinishRouter. -func InsertFilter(pattern string, pos int, filter FilterFunc) *App { - BeeApp.Handlers.InsertFilter(pattern, pos, filter) +// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter. +// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute) +func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App { + BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...) return BeeApp } diff --git a/filter.go b/filter.go index 294966d4..eebad329 100644 --- a/filter.go +++ b/filter.go @@ -17,9 +17,10 @@ package beego // FilterRouter defines filter operation before controller handler execution. // it can match patterned url and do filter function when action arrives. type FilterRouter struct { - filterFunc FilterFunc - tree *Tree - pattern string + filterFunc FilterFunc + tree *Tree + pattern string + returnOnOutput bool } // ValidRouter check current request is valid for this filter. diff --git a/router.go b/router.go index ddcf36c3..e22b5c1f 100644 --- a/router.go +++ b/router.go @@ -381,7 +381,9 @@ func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface) } // Add a FilterFunc with pattern rule and action constant. -func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter FilterFunc) error { +// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute) +func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error { + mr := new(FilterRouter) mr.tree = NewTree() mr.pattern = pattern @@ -389,6 +391,11 @@ func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter Filter if !RouterCaseSensitive { pattern = strings.ToLower(pattern) } + if params == nil { + mr.returnOnOutput = true + } else { + mr.returnOnOutput = params[0] + } mr.tree.AddRouter(pattern, true) return p.insertFilterRouter(pos, mr) } @@ -587,7 +594,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) if ok, p := filterR.ValidRouter(urlPath); ok { context.Input.Params = p filterR.filterFunc(context) - if w.started { + if filterR.returnOnOutput && w.started { return true } } diff --git a/router_test.go b/router_test.go index d378589b..c64bb191 100644 --- a/router_test.go +++ b/router_test.go @@ -17,6 +17,7 @@ package beego import ( "net/http" "net/http/httptest" + "strings" "testing" "github.com/astaxie/beego/context" @@ -385,3 +386,196 @@ func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request return recorder, request } + +// Execution point: BeforeRouter +// expectation: only BeforeRouter function is executed, notmatch output as router doesn't handle +func TestFilterBeforeRouter(t *testing.T) { + testName := "TestFilterBeforeRouter" + url := "/beforeRouter" + + mux := NewControllerRegister() + mux.InsertFilter(url, BeforeRouter, beegoBeforeRouter1) + + mux.Get(url, beegoFilterFunc) + + rw, r := testRequest("GET", url) + mux.ServeHTTP(rw, r) + + if strings.Contains(rw.Body.String(), "BeforeRouter1") == false { + t.Errorf(testName + " BeforeRouter did not run") + } + if strings.Contains(rw.Body.String(), "hello") == true { + t.Errorf(testName + " BeforeRouter did not return properly") + } +} + +// Execution point: BeforeExec +// expectation: only BeforeExec function is executed, match as router determines route only +func TestFilterBeforeExec(t *testing.T) { + testName := "TestFilterBeforeExec" + url := "/beforeExec" + + mux := NewControllerRegister() + mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) + mux.InsertFilter(url, BeforeExec, beegoBeforeExec1) + + mux.Get(url, beegoFilterFunc) + + rw, r := testRequest("GET", url) + mux.ServeHTTP(rw, r) + + if strings.Contains(rw.Body.String(), "BeforeExec1") == false { + t.Errorf(testName + " BeforeExec did not run") + } + if strings.Contains(rw.Body.String(), "hello") == true { + t.Errorf(testName + " BeforeExec did not return properly") + } + if strings.Contains(rw.Body.String(), "BeforeRouter") == true { + t.Errorf(testName + " BeforeRouter ran in error") + } +} + +// Execution point: AfterExec +// expectation: only AfterExec function is executed, match as router handles +func TestFilterAfterExec(t *testing.T) { + testName := "TestFilterAfterExec" + url := "/afterExec" + + mux := NewControllerRegister() + mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) + mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput) + mux.InsertFilter(url, AfterExec, beegoAfterExec1) + + mux.Get(url, beegoFilterFunc) + + rw, r := testRequest("GET", url) + mux.ServeHTTP(rw, r) + + if strings.Contains(rw.Body.String(), "AfterExec1") == false { + t.Errorf(testName + " AfterExec did not run") + } + if strings.Contains(rw.Body.String(), "hello") == false { + t.Errorf(testName + " handler did not run properly") + } + if strings.Contains(rw.Body.String(), "BeforeRouter") == true { + t.Errorf(testName + " BeforeRouter ran in error") + } + if strings.Contains(rw.Body.String(), "BeforeExec") == true { + t.Errorf(testName + " BeforeExec ran in error") + } +} + +// Execution point: FinishRouter +// expectation: only FinishRouter function is executed, match as router handles +func TestFilterFinishRouter(t *testing.T) { + testName := "TestFilterFinishRouter" + url := "/finishRouter" + + mux := NewControllerRegister() + mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) + mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput) + mux.InsertFilter(url, AfterExec, beegoFilterNoOutput) + mux.InsertFilter(url, FinishRouter, beegoFinishRouter1) + + mux.Get(url, beegoFilterFunc) + + rw, r := testRequest("GET", url) + mux.ServeHTTP(rw, r) + + if strings.Contains(rw.Body.String(), "FinishRouter1") == true { + t.Errorf(testName + " FinishRouter did not run") + } + if strings.Contains(rw.Body.String(), "hello") == false { + t.Errorf(testName + " handler did not run properly") + } + if strings.Contains(rw.Body.String(), "AfterExec1") == true { + t.Errorf(testName + " AfterExec ran in error") + } + if strings.Contains(rw.Body.String(), "BeforeRouter") == true { + t.Errorf(testName + " BeforeRouter ran in error") + } + if strings.Contains(rw.Body.String(), "BeforeExec") == true { + t.Errorf(testName + " BeforeExec ran in error") + } +} + +// Execution point: FinishRouter +// expectation: only first FinishRouter function is executed, match as router handles +func TestFilterFinishRouterMultiFirstOnly(t *testing.T) { + testName := "TestFilterFinishRouterMultiFirstOnly" + url := "/finishRouterMultiFirstOnly" + + mux := NewControllerRegister() + mux.InsertFilter(url, FinishRouter, beegoFinishRouter1) + mux.InsertFilter(url, FinishRouter, beegoFinishRouter2) + + mux.Get(url, beegoFilterFunc) + + rw, r := testRequest("GET", url) + mux.ServeHTTP(rw, r) + + if strings.Contains(rw.Body.String(), "FinishRouter1") == false { + t.Errorf(testName + " FinishRouter1 did not run") + } + if strings.Contains(rw.Body.String(), "hello") == false { + t.Errorf(testName + " handler did not run properly") + } + // not expected in body + if strings.Contains(rw.Body.String(), "FinishRouter2") == true { + t.Errorf(testName + " FinishRouter2 did run") + } +} + +// Execution point: FinishRouter +// expectation: both FinishRouter functions execute, match as router handles +func TestFilterFinishRouterMulti(t *testing.T) { + testName := "TestFilterFinishRouterMulti" + url := "/finishRouterMulti" + + mux := NewControllerRegister() + mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false) + mux.InsertFilter(url, FinishRouter, beegoFinishRouter2) + + mux.Get(url, beegoFilterFunc) + + rw, r := testRequest("GET", url) + mux.ServeHTTP(rw, r) + + if strings.Contains(rw.Body.String(), "FinishRouter1") == false { + t.Errorf(testName + " FinishRouter1 did not run") + } + if strings.Contains(rw.Body.String(), "hello") == false { + t.Errorf(testName + " handler did not run properly") + } + if strings.Contains(rw.Body.String(), "FinishRouter2") == false { + t.Errorf(testName + " FinishRouter2 did not run properly") + } +} + +func beegoFilterNoOutput(ctx *context.Context) { + return +} +func beegoBeforeRouter1(ctx *context.Context) { + ctx.WriteString("|BeforeRouter1") +} +func beegoBeforeRouter2(ctx *context.Context) { + ctx.WriteString("|BeforeRouter2") +} +func beegoBeforeExec1(ctx *context.Context) { + ctx.WriteString("|BeforeExec1") +} +func beegoBeforeExec2(ctx *context.Context) { + ctx.WriteString("|BeforeExec2") +} +func beegoAfterExec1(ctx *context.Context) { + ctx.WriteString("|AfterExec1") +} +func beegoAfterExec2(ctx *context.Context) { + ctx.WriteString("|AfterExec2") +} +func beegoFinishRouter1(ctx *context.Context) { + ctx.WriteString("|FinishRouter1") +} +func beegoFinishRouter2(ctx *context.Context) { + ctx.WriteString("|FinishRouter2") +}