minor fix required for the upcoming release

Former-commit-id: f04b770f93d7612941340af6e45d7d0516035e14
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-02-20 05:46:23 +02:00
parent 08403f0317
commit 027eb5d6da
5 changed files with 66 additions and 30 deletions

View File

@ -28,6 +28,8 @@ func newApp() *iris.Application {
}) })
// Different path parameters types in the same path. // Different path parameters types in the same path.
// Note that: fallback should registered first e.g. {path} {string},
// because the handler on this case is executing from last to top.
app.Get("/u/{p:path}", func(ctx iris.Context) { app.Get("/u/{p:path}", func(ctx iris.Context) {
ctx.Writef(":string, :int, :uint, :alphabetical and :path in the same path pattern.") ctx.Writef(":string, :int, :uint, :alphabetical and :path in the same path pattern.")
}) })
@ -39,6 +41,13 @@ func newApp() *iris.Application {
ctx.Writef("username (string): %s", ctx.Params().Get("username")) ctx.Writef("username (string): %s", ctx.Params().Get("username"))
}) })
app.Get("/u/{firstname:alphabetical}", func(ctx iris.Context) {
ctx.Writef("before firstname (alphabetical), current route name: %s\n", ctx.RouteName())
ctx.Next()
}, func(ctx iris.Context) {
ctx.Writef("firstname (alphabetical): %s", ctx.Params().Get("firstname"))
})
app.Get("/u/{id:int}", func(ctx iris.Context) { app.Get("/u/{id:int}", func(ctx iris.Context) {
ctx.Writef("before id (int), current route name: %s\n", ctx.RouteName()) ctx.Writef("before id (int), current route name: %s\n", ctx.RouteName())
ctx.Next() ctx.Next()
@ -53,13 +62,6 @@ func newApp() *iris.Application {
ctx.Writef("uid (uint): %d", ctx.Params().GetUintDefault("uid", 0)) ctx.Writef("uid (uint): %d", ctx.Params().GetUintDefault("uid", 0))
}) })
app.Get("/u/{firstname:alphabetical}", func(ctx iris.Context) {
ctx.Writef("before firstname (alphabetical), current route name: %s\n", ctx.RouteName())
ctx.Next()
}, func(ctx iris.Context) {
ctx.Writef("firstname (alphabetical): %s", ctx.Params().Get("firstname"))
})
/* /*
/u/some/path/here maps to :path /u/some/path/here maps to :path
/u/abcd maps to :alphabetical (if :alphabetical registered otherwise :string) /u/abcd maps to :alphabetical (if :alphabetical registered otherwise :string)

View File

@ -499,17 +499,17 @@ type Context interface {
// //
// If not found or parse errors returns the "def". // If not found or parse errors returns the "def".
PostValueInt64Default(name string, def int64) int64 PostValueInt64Default(name string, def int64) int64
// PostValueInt64Default returns the parsed form data from POST, PATCH, // PostValueFloat64 returns the parsed form data from POST, PATCH,
// or PUT body parameters based on a "name", as float64. // or PUT body parameters based on a "name", as float64.
// //
// If not found returns -1 and a non-nil error. // If not found returns -1 and a non-nil error.
PostValueFloat64(name string) (float64, error) PostValueFloat64(name string) (float64, error)
// PostValueInt64Default returns the parsed form data from POST, PATCH, // PostValueFloat64Default returns the parsed form data from POST, PATCH,
// or PUT body parameters based on a "name", as float64. // or PUT body parameters based on a "name", as float64.
// //
// If not found or parse errors returns the "def". // If not found or parse errors returns the "def".
PostValueFloat64Default(name string, def float64) float64 PostValueFloat64Default(name string, def float64) float64
// PostValueInt64Default returns the parsed form data from POST, PATCH, // PostValueBool returns the parsed form data from POST, PATCH,
// or PUT body parameters based on a "name", as bool. // or PUT body parameters based on a "name", as bool.
// //
// If not found or value is false, then it returns false, otherwise true. // If not found or value is false, then it returns false, otherwise true.
@ -2290,7 +2290,7 @@ func (ctx *context) PostValueInt64Default(name string, def int64) int64 {
return def return def
} }
// PostValueInt64Default returns the parsed form data from POST, PATCH, // PostValueFloat64 returns the parsed form data from POST, PATCH,
// or PUT body parameters based on a "name", as float64. // or PUT body parameters based on a "name", as float64.
// //
// If not found returns -1 and a non-nil error. // If not found returns -1 and a non-nil error.
@ -2302,7 +2302,7 @@ func (ctx *context) PostValueFloat64(name string) (float64, error) {
return strconv.ParseFloat(v, 64) return strconv.ParseFloat(v, 64)
} }
// PostValueInt64Default returns the parsed form data from POST, PATCH, // PostValueFloat64Default returns the parsed form data from POST, PATCH,
// or PUT body parameters based on a "name", as float64. // or PUT body parameters based on a "name", as float64.
// //
// If not found or parse errors returns the "def". // If not found or parse errors returns the "def".
@ -2314,7 +2314,7 @@ func (ctx *context) PostValueFloat64Default(name string, def float64) float64 {
return def return def
} }
// PostValueInt64Default returns the parsed form data from POST, PATCH, // PostValueBool returns the parsed form data from POST, PATCH,
// or PUT body parameters based on a "name", as bool. // or PUT body parameters based on a "name", as bool.
// //
// If not found or value is false, then it returns false, otherwise true. // If not found or value is false, then it returns false, otherwise true.

View File

@ -105,16 +105,21 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
// fixes order when wildcard root is registered before other wildcard paths // fixes order when wildcard root is registered before other wildcard paths
return true return true
} }
if secondSlashLen == firstSlashLen { if secondSlashLen == firstSlashLen {
// fixes order when static path with the same prefix with a wildcard path // fixes order when static path with the same prefix with a wildcard path
// is registered after the wildcard path, although this is managed // is registered after the wildcard path, although this is managed
// by the low-level node but it couldn't work if we registered a root level wildcard, this fixes it. // by the low-level node but it couldn't work if we registered a root level wildcard, this fixes it.
if len(first.Tmpl().Params) == 0 { if len(first.tmpl.Params) == 0 {
return false return false
} }
if len(second.Tmpl().Params) == 0 { if len(second.tmpl.Params) == 0 {
return true return true
} }
// No don't fix the order by framework's suggestion,
// let it as it is today; {string} and {path} should be registered before {id} {uint} and e.t.c.
// see `bindMultiParamTypesHandler` for the reason. Order of registration matters.
} }
} }
@ -151,6 +156,7 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
func bindMultiParamTypesHandler(top *Route, r *Route) { func bindMultiParamTypesHandler(top *Route, r *Route) {
r.BuildHandlers() r.BuildHandlers()
// println("here for top: " + top.Name + " and current route: " + r.Name)
h := r.Handlers[1:] // remove the macro evaluator handler as we manually check below. h := r.Handlers[1:] // remove the macro evaluator handler as we manually check below.
f := macroHandler.MakeFilter(r.tmpl) f := macroHandler.MakeFilter(r.tmpl)
if f == nil { if f == nil {
@ -158,8 +164,13 @@ func bindMultiParamTypesHandler(top *Route, r *Route) {
} }
decisionHandler := func(ctx context.Context) { decisionHandler := func(ctx context.Context) {
// println("core/router/handler.go: decision handler; " + ctx.Path() + " route.Name: " + r.Name + " vs context's " + ctx.GetCurrentRoute().Name())
currentRouteName := ctx.RouteName() currentRouteName := ctx.RouteName()
// Different path parameters types in the same path, fallback should registered first e.g. {path} {string},
// because the handler on this case is executing from last to top.
if f(ctx) { if f(ctx) {
// println("core/router/handler.go: filter for : " + r.Name + " passed")
ctx.SetCurrentRouteName(r.Name) ctx.SetCurrentRouteName(r.Name)
ctx.HandlerIndex(0) ctx.HandlerIndex(0)
ctx.Do(h) ctx.Do(h)

View File

@ -4,6 +4,7 @@ package handler
import ( import (
"github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/memstore"
"github.com/kataras/iris/v12/macro" "github.com/kataras/iris/v12/macro"
) )
@ -76,10 +77,33 @@ func MakeFilter(tmpl macro.Template) context.Filter {
return false return false
} }
if !p.Eval(entry.String(), &ctx.Params().Store) { value := p.Eval(entry.String())
if value == nil {
ctx.StatusCode(p.ErrCode) ctx.StatusCode(p.ErrCode)
return false return false
} }
// Fixes binding different path parameters names,
//
// app.Get("/{fullname:string}", strHandler)
// app.Get("/{id:int}", idHandler)
//
// before that user didn't see anything
// but under the hoods the set-ed value was a type of string instead of type of int,
// because store contained both "fullname" (which set-ed by the router itself on its string representation)
// and "id" by the param evaluator (see core/router/handler.go and bindMultiParamTypesHandler->MakeFilter)
// and the MVC get by index (e.g. 0) therefore
// it got the "fullname" of type string instead of "id" int if /{int} requested.
// which is critical for faster type assertion in the upcoming, new iris dependency injection (20 Feb 2020).
ctx.Params().Store[p.Index] = memstore.Entry{
Key: p.Name,
ValueRaw: value,
}
// for i, v := range ctx.Params().Store {
// fmt.Printf("[%d:%s] macro/handler/handler.go: param passed: %s(%v of type: %T)\n", i, v.Key,
// p.Src, v.ValueRaw, v.ValueRaw)
// }
} }
return true return true

View File

@ -3,7 +3,6 @@ package macro
import ( import (
"reflect" "reflect"
"github.com/kataras/iris/v12/core/memstore"
"github.com/kataras/iris/v12/macro/interpreter/ast" "github.com/kataras/iris/v12/macro/interpreter/ast"
"github.com/kataras/iris/v12/macro/interpreter/parser" "github.com/kataras/iris/v12/macro/interpreter/parser"
) )
@ -65,29 +64,28 @@ func (p *TemplateParam) CanEval() bool {
return p.canEval return p.canEval
} }
// Eval is the most critical part of the TEmplateParam. // Eval is the most critical part of the TemplateParam.
// It is responsible to return "passed:true" or "not passed:false" // It is responsible to return the type-based value if passed otherwise nil.
// if the "paramValue" is the correct type of the registered parameter type // If the "paramValue" is the correct type of the registered parameter type
// and all functions, if any, are passed. // and all functions, if any, are passed.
// "paramChanger" is the same form of context's Params().Set
// we could accept a memstore.Store or even context.RequestParams
// but this form has been chosed in order to test easier and fully decoupled from a request when necessary.
// //
// It is called from the converted macro handler (middleware) // It is called from the converted macro handler (middleware)
// from the higher-level component of "kataras/iris/macro/handler#MakeHandler". // from the higher-level component of "kataras/iris/macro/handler#MakeHandler".
func (p *TemplateParam) Eval(paramValue string, paramSetter memstore.ValueSetter) bool { func (p *TemplateParam) Eval(paramValue string) interface{} {
if p.TypeEvaluator == nil { if p.TypeEvaluator == nil {
for _, fn := range p.stringInFuncs { for _, fn := range p.stringInFuncs {
if !fn(paramValue) { if !fn(paramValue) {
return false return nil
} }
} }
return true return paramValue
} }
// fmt.Printf("macro/template.go#L88: Eval for param value: %s and p.Src: %s\n", paramValue, p.Src)
newValue, passed := p.TypeEvaluator(paramValue) newValue, passed := p.TypeEvaluator(paramValue)
if !passed { if !passed {
return false return nil
} }
if len(p.Funcs) > 0 { if len(p.Funcs) > 0 {
@ -96,13 +94,14 @@ func (p *TemplateParam) Eval(paramValue string, paramSetter memstore.ValueSetter
// or make it as func(interface{}) bool and pass directly the "newValue" // or make it as func(interface{}) bool and pass directly the "newValue"
// but that would not be as easy for end-developer, so keep that "slower": // but that would not be as easy for end-developer, so keep that "slower":
if !evalFunc.Call(paramIn)[0].Interface().(bool) { // i.e func(paramValue int) bool if !evalFunc.Call(paramIn)[0].Interface().(bool) { // i.e func(paramValue int) bool
return false return nil
} }
} }
} }
paramSetter.Set(p.Name, newValue) // fmt.Printf("macro/template.go: passed with value: %v and type: %T\n", newValue, newValue)
return true
return newValue
} }
// Parse takes a full route path and a macro map (macro map contains the macro types with their registered param functions) // Parse takes a full route path and a macro map (macro map contains the macro types with their registered param functions)