diff --git a/hero/di/object.go b/hero/di/object.go index 385162bd8..047d73620 100644 --- a/hero/di/object.go +++ b/hero/di/object.go @@ -77,8 +77,10 @@ func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker) (func([]reflect.Val return nil, typ, errBad } - // invalid if not returns one single value. - if typ.NumOut() != 1 { + n := typ.NumOut() + + // invalid if not returns one single value or two values but the second is not an error. + if !(n == 1 || (n == 2 && IsError(typ.Out(1)))) { return nil, typ, errBad } @@ -88,19 +90,36 @@ func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker) (func([]reflect.Val } } - outTyp := typ.Out(0) - zeroOutVal := reflect.New(outTyp).Elem() + firstOutTyp := typ.Out(0) + firstZeroOutVal := reflect.New(firstOutTyp).Elem() bf := func(ctxValue []reflect.Value) reflect.Value { results := fn.Call(ctxValue) - if len(results) == 0 { - return zeroOutVal - } v := results[0] - if !v.IsValid() { - return zeroOutVal + if !v.IsValid() { // check the first value, second is error. + return firstZeroOutVal } + + if n == 2 { + // two, second is always error. + errVal := results[1] + if !errVal.IsNil() { + // error is not nil, do something with it. + if ctx, ok := ctxValue[0].Interface().(interface { + StatusCode(int) + WriteString(string) (int, error) + StopExecution() + }); ok { + ctx.StatusCode(400) + ctx.WriteString(errVal.Interface().(error).Error()) + ctx.StopExecution() + } + + return firstZeroOutVal + } + } + // if v.String() == "" { // println("di/object.go: " + v.String()) // // println("di/object.go: because it's interface{} it should be returned as: " + v.Elem().Type().String() + " and its value: " + v.Elem().Interface().(string)) @@ -109,7 +128,7 @@ func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker) (func([]reflect.Val return v } - return bf, outTyp, nil + return bf, firstOutTyp, nil } // IsAssignable checks if "to" type can be used as "b.Value/ReturnValue". diff --git a/hero/di/reflect.go b/hero/di/reflect.go index 08fc7f2a7..e2c687007 100644 --- a/hero/di/reflect.go +++ b/hero/di/reflect.go @@ -59,6 +59,13 @@ func IsZero(v reflect.Value) bool { return v.Interface() == zero.Interface() } +var errTyp = reflect.TypeOf((*error)(nil)).Elem() + +// IsError returns true if "typ" is type of `error`. +func IsError(typ reflect.Type) bool { + return typ.Implements(errTyp) +} + // IndirectValue returns the reflect.Value that "v" points to. // If "v" is a nil pointer, Indirect returns a zero Value. // If "v" is not a pointer, Indirect returns v. diff --git a/mvc/controller.go b/mvc/controller.go index 804b1b004..cb0cbd9dc 100644 --- a/mvc/controller.go +++ b/mvc/controller.go @@ -398,6 +398,10 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref in[0] = ctrl funcInjector.Inject(&in, ctxValue) + if ctx.IsStopped() { + return // stop as soon as possible, although it would stop later on if `ctx.StopExecution` called. + } + // for idxx, inn := range in { // println("controller.go: execution: in.Value = "+inn.String()+" and in.Type = "+inn.Type().Kind().String()+" of index: ", idxx) // } diff --git a/mvc/controller_test.go b/mvc/controller_test.go index 7103c9e94..eb41ab7a4 100644 --- a/mvc/controller_test.go +++ b/mvc/controller_test.go @@ -272,11 +272,22 @@ type testControllerBindDeep struct { testControllerBindStruct } +func (t *testControllerBindDeep) BeforeActivation(b BeforeActivation) { + b.Dependencies().Add(func(ctx iris.Context) (v testCustomStruct, err error) { + err = ctx.ReadJSON(&v) + return + }) +} + func (t *testControllerBindDeep) Get() { // t.testControllerBindStruct.Get() t.Ctx.Writef(t.TitlePointer.title + t.TitleValue.title + t.Other) } +func (t *testControllerBindDeep) Post(v testCustomStruct) string { + return v.Name +} + func TestControllerDependencies(t *testing.T) { app := iris.New() // app.Logger().SetLevel("debug") @@ -299,6 +310,12 @@ func TestControllerDependencies(t *testing.T) { e.GET("/deep").Expect().Status(iris.StatusOK). Body().Equal(expected) + + e.POST("/deep").WithJSON(iris.Map{"name": "kataras"}).Expect().Status(iris.StatusOK). + Body().Equal("kataras") + + e.POST("/deep").Expect().Status(iris.StatusBadRequest). + Body().Equal("unexpected end of JSON input") } type testCtrl0 struct { diff --git a/websocket/connection.go b/websocket/connection.go index b2b7afaba..8a8a416be 100644 --- a/websocket/connection.go +++ b/websocket/connection.go @@ -808,7 +808,7 @@ func DialContext(ctx stdContext.Context, url string, cfg ConnectionConfig) (Clie ctx = stdContext.Background() } - if !strings.HasPrefix(url, "ws://") { + if !strings.HasPrefix(url, "ws://") || !strings.HasPrefix(url, "wss://") { url = "ws://" + url }