1
0
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:
Gerasimos (Makis) Maropoulos
2020-08-09 22:28:44 +03:00
parent 24de7bf7fb
commit da029d6f37
3 changed files with 102 additions and 35 deletions

View File

@@ -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

View File

@@ -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")
}