fix Context.Proceed called on last handler in the chain

relative: https://github.com/kataras/iris/issues/1581#issuecomment-673958152
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-08-14 11:53:38 +03:00
parent 28b39efa7d
commit 5f235993ee
No known key found for this signature in database
GPG Key ID: 5DBE766BD26A54E7
2 changed files with 31 additions and 6 deletions

View File

@ -122,6 +122,12 @@ type Context struct {
handlers Handlers
// the current position of the handler's chain
currentHandlerIndex int
// proceeded reports whether `Proceed` method
// called before a `Next`. It is a flash field and it is set
// to true on `Next` call when its called on the last handler in the chain.
// Reports whether a `Next` is called,
// even if the handler index remains the same (last handler).
proceeded uint32
}
// NewContext returns a new Context instance.
@ -149,6 +155,7 @@ func (ctx *Context) Clone() *Context {
writer: ctx.writer.Clone(),
request: ctx.request,
currentHandlerIndex: stopExecutionIndex,
proceeded: atomic.LoadUint32(&ctx.proceeded),
currentRoute: ctx.currentRoute,
}
}
@ -170,6 +177,7 @@ func (ctx *Context) BeginRequest(w http.ResponseWriter, r *http.Request) {
ctx.params.Store = ctx.params.Store[0:0]
ctx.request = r
ctx.currentHandlerIndex = 0
ctx.proceeded = 0
ctx.writer = AcquireResponseWriter()
ctx.writer.BeginResponse(w)
}
@ -430,7 +438,10 @@ func (ctx *Context) HandlerIndex(n int) (currentIndex int) {
}
// Proceed is an alternative way to check if a particular handler
// has been executed and called the `ctx.Next` function inside it.
// has been executed.
// The given "h" Handler can report a failure with `StopXXX` methods
// or ignore calling a `Next` (see `iris.ExecutionRules` too).
//
// This is useful only when you run a handler inside
// another handler. It justs checks for before index and the after index.
//
@ -467,13 +478,25 @@ func (ctx *Context) HandlerIndex(n int) (currentIndex int) {
// Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
func (ctx *Context) Proceed(h Handler) bool {
beforeIdx := ctx.currentHandlerIndex
atomic.StoreUint32(&ctx.proceeded, 0)
h(ctx)
if ctx.currentHandlerIndex > beforeIdx && !ctx.IsStopped() {
return true
}
if ctx.currentHandlerIndex == stopExecutionIndex {
return false
}
if ctx.currentHandlerIndex <= beforeIdx {
// If "h" didn't call its Next
// or it doesn't have a next handler,
// that index will be the same,
// so we check if at least once the
// Next is called on the last handler.
return atomic.CompareAndSwapUint32(&ctx.proceeded, 1, 0)
}
return true
}
// HandlerName returns the current handler's name, helpful for debugging.
func (ctx *Context) HandlerName() string {
return HandlerName(ctx.handlers[ctx.currentHandlerIndex])
@ -505,7 +528,9 @@ func (ctx *Context) Next() {
nextIndex := ctx.currentHandlerIndex + 1
handlers := ctx.handlers
if nextIndex < len(handlers) {
if n := len(handlers); nextIndex == n {
atomic.StoreUint32(&ctx.proceeded, 1) // last handler but Next is called.
} else if nextIndex < n {
ctx.currentHandlerIndex = nextIndex
handlers[nextIndex](ctx)
}

View File

@ -36,7 +36,7 @@ var (
firstUseRouterResponse = "userouter1"
// Use inline handler, no the `writeHandler`,
// because it will be overriden by `secondUseRouterHandler` otherwise,
// because it will be overridden by `secondUseRouterHandler` otherwise,
// look `UseRouter:context.UpsertHandlers` for more.
firstUseRouterHandler = func(ctx iris.Context) {
ctx.WriteString(firstUseRouterResponse)