package revel // An "interceptor" is functionality invoked by the framework BEFORE or AFTER // an action. // // An interceptor may optionally return a Result (instead of nil). Depending on // when the interceptor was invoked, the response is different: // 1. BEFORE: No further interceptors are invoked, and neither is the action. // 2. AFTER: Further interceptors are still run. // In all cases, any returned Result will take the place of any existing Result. // // In the BEFORE case, that returned Result is guaranteed to be final, while // in the AFTER case it is possible that a further interceptor could emit its // own Result. // // Interceptors are called in the order that they are added. // // *** // // Two types of interceptors are provided: Funcs and Methods // // Func Interceptors may apply to any / all Controllers. // // func example(*revel.Controller) revel.Result // // Method Interceptors are provided so that properties can be set on application // controllers. // // func (c AppController) example() revel.Result // func (c *AppController) example() revel.Result // type InterceptorFunc func(*Controller) Result type InterceptorMethod interface{} type When int const ( BEFORE When = iota AFTER PANIC FINALLY ) type InterceptTarget int const ( ALL_CONTROLLERS InterceptTarget = iota ) type Interception struct { When When } // Perform the given interception. // val is a pointer to the App Controller. func (i Interception) Invoke(val reflect.Value) reflect.Value { var arg reflect.Value if i.function == nil { // If it's an InterceptorMethod, then we have to pass in the target type. arg = findTarget(val, i.target) } else { // If it's an InterceptorFunc, then the type must be *Controller. // We can find that by following the embedded types up the chain. for val.Type() != controllerPtrType { if val.Kind() == reflect.Ptr { val = val.Elem() } val = val.Field(0) } arg = val } vals := i.callable.Call([]reflect.Value{arg}) return vals[0] } func InterceptorFilter(c *Controller, fc []Filter) { defer invokeInterceptors(FINALLY, c) defer func() { if err := recover(); err != nil { invokeInterceptors(PANIC, c) panic(err) } }() // Invoke the BEFORE interceptors and return early, if we get a result. invokeInterceptors(BEFORE, c) if c.Result != nil { return } fc[0](c, fc[1:]) invokeInterceptors(AFTER, c) } // Install a general interceptor. // This can be applied to any Controller. // It must have the signature of: // func example(c *revel.Controller) revel.Result func InterceptFunc(intc InterceptorFunc, when When, target interface{}) { interceptors = append(interceptors, &Interception{ When: when, function: intc, callable: reflect.ValueOf(intc), target: reflect.TypeOf(target), interceptAll: target == ALL_CONTROLLERS, }) } // Install an interceptor method that applies to its own Controller. // func (c AppController) example() revel.Result // func (c *AppController) example() revel.Result func InterceptMethod(intc InterceptorMethod, when When) { methodType := reflect.TypeOf(intc) if methodType.Kind() != reflect.Func || methodType.NumOut() != 1 || methodType.NumIn() != 1 { log.Fatalln("Interceptor method should have signature like", "'func (c *AppController) example() revel.Result' but was", methodType) } interceptors = append(interceptors, &Interception{ When: when, method: intc, callable: reflect.ValueOf(intc), target: methodType.In(0), }) }