mirror of
https://github.com/kataras/iris.git
synced 2026-01-20 18:35:57 +00:00
New 'Application.UseRouter(...Handler)'. Read HISTORY.md
This commit is contained in:
@@ -18,7 +18,8 @@ import (
|
||||
// User can refresh the router with `RefreshRouter` whenever a route's field is changed by him.
|
||||
type Router struct {
|
||||
mu sync.Mutex // for Downgrade, WrapRouter & BuildRouter,
|
||||
// not indeed but we don't to risk its usage by third-parties.
|
||||
|
||||
preHandlers context.Handlers // run before requestHandler, as middleware, same way context's handlers run, see `UseRouter`.
|
||||
requestHandler RequestHandler // build-accessible, can be changed to define a custom router or proxy, used on RefreshRouter too.
|
||||
mainHandler http.HandlerFunc // init-accessible
|
||||
wrapperFunc WrapperFunc
|
||||
@@ -86,6 +87,25 @@ func (router *Router) FindClosestPaths(subdomain, searchPath string, n int) []st
|
||||
return list
|
||||
}
|
||||
|
||||
// UseRouter registers one or more handlers that are fired
|
||||
// before the main router's request handler.
|
||||
//
|
||||
// Use this method to register handlers, that can ran
|
||||
// independently of the incoming request's method and path values,
|
||||
// that they will be executed ALWAYS against ALL incoming requests.
|
||||
// Example of use-case: CORS.
|
||||
//
|
||||
// Note that because these are executed before the router itself
|
||||
// the Context should not have access to the `GetCurrentRoute`
|
||||
// as it is not decided yet which route is responsible to handle the incoming request.
|
||||
// It's one level higher than the `WrapRouter`.
|
||||
// The context SHOULD call its `Next` method in order to proceed to
|
||||
// the next handler in the chain or the main request handler one.
|
||||
// ExecutionRules are NOT applied here.
|
||||
func (router *Router) UseRouter(handlers ...context.Handler) {
|
||||
router.preHandlers = append(router.preHandlers, handlers...)
|
||||
}
|
||||
|
||||
// BuildRouter builds the router based on
|
||||
// the context factory (explicit pool in this case),
|
||||
// the request handler which manages how the main handler will multiplexes the routes
|
||||
@@ -130,12 +150,27 @@ func (router *Router) BuildRouter(cPool *context.Pool, requestHandler RequestHan
|
||||
}
|
||||
|
||||
// the important
|
||||
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := cPool.Acquire(w, r)
|
||||
// Note: we can't get all r.Context().Value key-value pairs
|
||||
// and save them to ctx.values.
|
||||
router.requestHandler.HandleRequest(ctx)
|
||||
cPool.Release(ctx)
|
||||
if len(router.preHandlers) > 0 {
|
||||
handlers := append(router.preHandlers, func(ctx *context.Context) {
|
||||
// set the handler index back to 0 so the route's handlers can be executed as exepcted.
|
||||
ctx.HandlerIndex(0)
|
||||
// execute the main request handler, this will fire the found route's handlers
|
||||
// or if error the error code's associated handler.
|
||||
router.requestHandler.HandleRequest(ctx)
|
||||
})
|
||||
|
||||
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := cPool.Acquire(w, r)
|
||||
// execute the final handlers chain.
|
||||
ctx.Do(handlers)
|
||||
cPool.Release(ctx)
|
||||
}
|
||||
} else {
|
||||
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := cPool.Acquire(w, r)
|
||||
router.requestHandler.HandleRequest(ctx)
|
||||
cPool.Release(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if router.wrapperFunc != nil { // if wrapper used then attach that as the router service
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
@@ -19,48 +18,43 @@ import (
|
||||
// with a different order but the route's final
|
||||
// response should be the same at all cases.
|
||||
var (
|
||||
mainResponse = "main"
|
||||
mainHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(mainResponse)
|
||||
ctx.Next()
|
||||
writeHandler = func(s string) iris.Handler {
|
||||
return func(ctx iris.Context) {
|
||||
ctx.WriteString(s)
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
|
||||
mainResponse = "main"
|
||||
mainHandler = writeHandler(mainResponse)
|
||||
|
||||
firstUseResponse = "use1"
|
||||
firstUseHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(firstUseResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
firstUseHandler = writeHandler(firstUseResponse)
|
||||
|
||||
secondUseResponse = "use2"
|
||||
secondUseHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(secondUseResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
secondUseHandler = writeHandler(secondUseResponse)
|
||||
|
||||
firstUseRouterResponse = "userouter1"
|
||||
firstUseRouterHandler = writeHandler(firstUseRouterResponse)
|
||||
|
||||
secondUseRouterResponse = "userouter2"
|
||||
secondUseRouterHandler = writeHandler(secondUseRouterResponse)
|
||||
|
||||
firstUseGlobalResponse = "useglobal1"
|
||||
firstUseGlobalHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(firstUseGlobalResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
firstUseGlobalHandler = writeHandler(firstUseGlobalResponse)
|
||||
|
||||
secondUseGlobalResponse = "useglobal2"
|
||||
secondUseGlobalHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(secondUseGlobalResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
secondUseGlobalHandler = writeHandler(secondUseGlobalResponse)
|
||||
|
||||
firstDoneResponse = "done1"
|
||||
firstDoneHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(firstDoneResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
firstDoneHandler = writeHandler(firstDoneResponse)
|
||||
|
||||
secondDoneResponse = "done2"
|
||||
secondDoneHandler = func(ctx *context.Context) {
|
||||
secondDoneHandler = func(ctx iris.Context) {
|
||||
ctx.WriteString(secondDoneResponse)
|
||||
}
|
||||
|
||||
finalResponse = firstUseGlobalResponse + secondUseGlobalResponse +
|
||||
finalResponse = firstUseRouterResponse + secondUseRouterResponse + firstUseGlobalResponse + secondUseGlobalResponse +
|
||||
firstUseResponse + secondUseResponse + mainResponse + firstDoneResponse + secondDoneResponse
|
||||
|
||||
testResponse = func(t *testing.T, app *iris.Application, path string) {
|
||||
@@ -73,6 +67,9 @@ var (
|
||||
|
||||
func TestMiddlewareByRouteDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler)
|
||||
app.UseRouter(secondUseRouterHandler)
|
||||
|
||||
app.Get("/mypath", firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler,
|
||||
mainHandler, firstDoneHandler, secondDoneHandler)
|
||||
|
||||
@@ -81,6 +78,7 @@ func TestMiddlewareByRouteDef(t *testing.T) {
|
||||
|
||||
func TestMiddlewareByUseAndDoneDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
app.Use(firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
@@ -91,12 +89,14 @@ func TestMiddlewareByUseAndDoneDef(t *testing.T) {
|
||||
|
||||
func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
// if failed then UseGlobal didnt' registered these handlers even before the
|
||||
// existing middleware.
|
||||
app.UseGlobal(firstUseGlobalHandler, secondUseGlobalHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
app.Get("/mypath", mainHandler)
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
@@ -104,6 +104,7 @@ func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) {
|
||||
|
||||
func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
@@ -123,6 +124,8 @@ func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) {
|
||||
|
||||
func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler)
|
||||
app.UseRouter(secondUseRouterHandler)
|
||||
|
||||
app.UseGlobal(firstUseGlobalHandler)
|
||||
app.UseGlobal(secondUseGlobalHandler)
|
||||
@@ -137,6 +140,7 @@ func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) {
|
||||
|
||||
func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||
app.Done(firstDoneHandler, secondDoneHandler)
|
||||
|
||||
app.Use(firstUseHandler, secondUseHandler)
|
||||
@@ -148,3 +152,29 @@ func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) {
|
||||
|
||||
testResponse(t, app, "/mypath")
|
||||
}
|
||||
|
||||
func TestUseRouterStopExecution(t *testing.T) {
|
||||
app := iris.New()
|
||||
app.UseRouter(func(ctx iris.Context) {
|
||||
ctx.WriteString("stop")
|
||||
// no ctx.Next, so the router has not even the chance to work.
|
||||
})
|
||||
app.Get("/", writeHandler("index"))
|
||||
|
||||
e := httptest.New(t, app)
|
||||
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal("stop")
|
||||
|
||||
app = iris.New()
|
||||
app.OnErrorCode(iris.StatusForbidden, func(ctx iris.Context) {
|
||||
ctx.Writef("err: %v", ctx.GetErr())
|
||||
})
|
||||
app.UseRouter(func(ctx iris.Context) {
|
||||
ctx.StopWithPlainError(iris.StatusForbidden, fmt.Errorf("custom error"))
|
||||
// stopped but not data written yet, the error code handler
|
||||
// should be responsible of it (use StopWithError to write and close).
|
||||
})
|
||||
app.Get("/", writeHandler("index"))
|
||||
|
||||
e = httptest.New(t, app)
|
||||
e.GET("/").Expect().Status(iris.StatusForbidden).Body().Equal("err: custom error")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user