1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-19 10:57:05 +00:00

General Improvements (UseRouter per Party, fix AutoTLS). Read HISTORY.md

relative to: https://github.com/kataras/iris/issues/1577 and https://github.com/kataras/iris/issues/1578
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-08-12 07:20:07 +03:00
parent da029d6f37
commit 0761bc35ee
15 changed files with 639 additions and 120 deletions

View File

@@ -3,6 +3,8 @@ package router
import (
"errors"
"net/http"
"sort"
"strings"
"sync"
"github.com/kataras/iris/v12/context"
@@ -19,7 +21,6 @@ import (
type Router struct {
mu sync.Mutex // for Downgrade, WrapRouter & BuildRouter,
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
@@ -87,23 +88,78 @@ 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...)
func (router *Router) buildMainHandlerWithFilters(routerFilters map[Party]*Filter, cPool *context.Pool, requestHandler RequestHandler) {
sortedFilters := make([]*Filter, 0, len(routerFilters))
// key was just there to enforce uniqueness on API level.
for _, f := range routerFilters {
sortedFilters = append(sortedFilters, f)
// append it as one handlers so execution rules are being respected in that step too.
f.Handlers = append(f.Handlers, func(ctx *context.Context) {
// set the handler index back to 0 so the route's handlers can be executed as expected.
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)
})
}
sort.SliceStable(sortedFilters, func(i, j int) bool {
left, right := sortedFilters[i], sortedFilters[j]
var (
leftSubLen = len(left.Subdomain)
rightSubLen = len(right.Subdomain)
leftSlashLen = strings.Count(left.Path, "/")
rightSlashLen = strings.Count(right.Path, "/")
)
if leftSubLen == rightSubLen {
if leftSlashLen > rightSlashLen {
return true
}
}
if leftSubLen > rightSubLen {
return true
}
if leftSlashLen > rightSlashLen {
return true
}
if leftSlashLen == rightSlashLen {
if len(left.Path) > len(right.Path) {
return true
}
return false
}
return len(left.Path) > len(right.Path)
})
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
ctx := cPool.Acquire(w, r)
filterExecuted := false
for _, f := range sortedFilters {
// fmt.Printf("Sorted filter execution: [%s] [%s]\n", f.Subdomain, f.Path)
if f.Matcher.Match(ctx) {
// fmt.Printf("Matched [%s] and execute [%d] handlers [%s]\n\n", ctx.Path(), len(f.Handlers), context.HandlersNames(f.Handlers))
filterExecuted = true
// execute the final handlers chain.
ctx.Do(f.Handlers)
break
}
}
if !filterExecuted {
// If not at least one match filter found and executed,
// then just run the router.
router.requestHandler.HandleRequest(ctx)
}
cPool.Release(ctx)
}
}
// BuildRouter builds the router based on
@@ -149,22 +205,9 @@ func (router *Router) BuildRouter(cPool *context.Pool, requestHandler RequestHan
}
}
// the important
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)
}
// the important stuff.
if routerFilters := routesProvider.GetRouterFilters(); len(routerFilters) > 0 {
router.buildMainHandlerWithFilters(routerFilters, cPool, requestHandler)
} else {
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
ctx := cPool.Acquire(w, r)