diff --git a/HISTORY.md b/HISTORY.md index 3b894a05..5e87a2e8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,41 @@ **How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`. +**NOTICE**: +The next Iris version will be released **when go v1.8 stable** will be ready (it's a matter of days). + + +The future version will include a ton of new features and fixes. + +Users should prepare their apps for: + +- Remove: the deprecated `.API`, it should be removed after v5(look on the v5 history tag), it's already removed from book after v5. + +- **MOST IMPORTANT: REMOVE** Package-level exported `iris.Default's methods and variables`, `iris.Default` will exists but methods like `iris.Handle` should be replace with `iris.Default.Handle` or `app := iris.New(); app.Handle(...); // like before, these will never change`. + - Why? + + Users often asked questions about built'n features and functions usage because they are being confused of the big public API (`iris.` vs `app := iris.New(); app.`). + This removal will also let me to describe the types with more sense. + +- NEW feature: `app.Adapt(iris.Policy)` which you will be able to adapt a **custom http router**, **custom template functions**, **custom http router wrappers**, **flow events** and much more. I'll cover these on book and examples when it will be released. + +- Replace: `.Plugins.` with `EventPolicy`: `app.Adapt(iris.EventPolicy{ Boot: func(*iris.Framework){}} )`. + +- Replace: `.AcquireCtx/.ReleaseCtx` with `app.Context.Acquire/Release/Run`. + +- NEW feature: able to pass an `func(http.ResponseWriter, *http.Request, http.HandlerFunc)` third-party net/http middleware like normal +iris.HandlerFunc with `iris.ToHandler`. (I already pushed that to the current version, because I think it will make your life easier now). + +- FIX: `iris run main.go` didn't reload the app on file changes when saving a source file via some IDEs, +because they do override the operating system's fs signals. The majority of +editors worked before but I couldn't let some developers without support. (I already pushed that to the current version) + +- FIX: custom routers not working well with static file serving, reverse routing and per-party http custom errors. + +- NEW: HTTP/2 Push `context.Push` + +The full list of next version's features among with one by one steps to refactor your code in breaking-cases will be noticed here when it will be released. + ## 6.1.2 -> 6.1.3 - Added a configuration field `iris.Config.DisableBodyConsumptionOnUnmarshal` diff --git a/context.go b/context.go index e7a9c4b3..3972d20a 100644 --- a/context.go +++ b/context.go @@ -162,6 +162,21 @@ func (ctx *Context) Next() { } } +// NextHandler returns the next handler in the chain (ctx.Middleware) +// otherwise nil. +// Notes: +// If the result of NextHandler() will be executed then +// the ctx.Pos (which is exported for these reasons) should be manually increment(++) +// otherwise your app will visit twice the same handler. +func (ctx *Context) NextHandler() Handler { + nextPos := ctx.Pos + 1 + // check if it has a next middleware + if nextPos < len(ctx.Middleware) { + return ctx.Middleware[nextPos] + } + return nil +} + // StopExecution just sets the .pos to 255 in order to not move to the next middlewares(if any) func (ctx *Context) StopExecution() { ctx.Pos = stopExecutionPosition diff --git a/http.go b/http.go index ef2eccaa..3d85f33a 100644 --- a/http.go +++ b/http.go @@ -189,9 +189,15 @@ func StatusText(code int) string { return statusText[code] } -// errHandler returns na error with message: 'Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context) +// errHandler returns na error with message: 'Passed argument is not func(*Context) neither an object which implements the iris.Default.Handler with Serve(ctx *Context) // It seems to be a +type Points to: +pointer.' -var errHandler = errors.New("Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)\n It seems to be a %T Points to: %v.") +var errHandler = errors.New(` +Passed argument is not an iris.Handler (or func(*iris.Context)) neither one of these types: + - http.Handler + - func(w http.ResponseWriter, r *http.Request) + - func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) + --------------------------------------------------------------------- +It seems to be a %T points to: %v`) type ( // Handler the main Iris Handler interface. @@ -217,37 +223,103 @@ func (h HandlerFunc) Serve(ctx *Context) { } // ToNativeHandler converts an iris handler to http.Handler -func ToNativeHandler(station *Framework, h Handler) http.Handler { +func ToNativeHandler(s *Framework, h Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := station.AcquireCtx(w, r) + ctx := s.AcquireCtx(w, r) h.Serve(ctx) - station.ReleaseCtx(ctx) + s.ReleaseCtx(ctx) }) } -// ToHandler converts an http.Handler/HandlerFunc to iris.Handler(Func) +// ToHandler converts different type styles of handlers that you +// used to use (usually with third-party net/http middleware) to an iris.HandlerFunc. +// +// Supported types: +// - .ToHandler(h http.Handler) +// - .ToHandler(func(w http.ResponseWriter, r *http.Request)) +// - .ToHandler(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)) func ToHandler(handler interface{}) HandlerFunc { - - //this is not the best way to do it, but I dont have any options right now. switch handler.(type) { case HandlerFunc: - //it's already an iris handler - return handler.(HandlerFunc) - case http.Handler: - //it's http.Handler - h := handler.(http.Handler) - return func(ctx *Context) { - h.ServeHTTP(ctx.ResponseWriter, ctx.Request) + { + // + //it's already an iris handler + // + return handler.(HandlerFunc) } + + case http.Handler: + // + // handlerFunc.ServeHTTP(w,r) + // + { + h := handler.(http.Handler) + return func(ctx *Context) { + h.ServeHTTP(ctx.ResponseWriter, ctx.Request) + } + } + case func(http.ResponseWriter, *http.Request): - return ToHandler(http.HandlerFunc(handler.(func(http.ResponseWriter, *http.Request)))) - //for func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc): READ iris-conrib/middleware/README.md for details + { + // + // handlerFunc(w,r) + // + return ToHandler(http.HandlerFunc(handler.(func(http.ResponseWriter, *http.Request)))) + } + + case func(http.ResponseWriter, *http.Request, http.HandlerFunc): + { + // + // handlerFunc(w,r, http.HandlerFunc) + // + return toHandlerNextHTTPHandlerFunc(handler.(func(http.ResponseWriter, *http.Request, http.HandlerFunc))) + } + default: - panic(errHandler.Format(handler, handler)) + { + // + // No valid handler passed + // + panic(errHandler.Format(handler, handler)) + } + } } +func toHandlerNextHTTPHandlerFunc(h func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)) HandlerFunc { + return HandlerFunc(func(ctx *Context) { + // take the next handler in route's chain + nextIrisHandler := ctx.NextHandler() + if nextIrisHandler != nil { + executed := false // we need to watch this in order to StopExecution from all next handlers + // if this next handler is not executed by the third-party net/http next-style middleware. + nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + nextIrisHandler.Serve(ctx) + executed = true + }) + + h(ctx.ResponseWriter, ctx.Request, nextHandler) + + // after third-party middleware's job: + if executed { + // if next is executed then increment the ctx.Pos manually + // in order to the next handler not to be executed twice. + ctx.Pos++ + } else { + // otherwise StopExecution from all next handlers. + ctx.StopExecution() + } + return + } + + // if not next handler found then this is not a 'valid' middleware but + // some middleware may don't care about next, + // so we just execute the handler with an empty net. + h(ctx.ResponseWriter, ctx.Request, http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) + }) +} + // convertToHandlers just make []HandlerFunc to []Handler, although HandlerFunc and Handler are the same // we need this on some cases we explicit want a interface Handler, it is useless for users. func convertToHandlers(handlersFn []HandlerFunc) []Handler { diff --git a/iris/run.go b/iris/run.go index 96522406..f1b1bafb 100644 --- a/iris/run.go +++ b/iris/run.go @@ -27,17 +27,8 @@ func run(cli.Flags) error { } func runAndWatch(programPath string) { - /* - project := rizla.NewProject(programPath) - project.Name = "IRIS" - project.AllowReloadAfter = time.Duration(3) * time.Second - project.Out = rizla.NewPrinter(os.Stdout) - project.Err = rizla.NewPrinter(os.Stderr) - rizla.Add(project) - - rizla.Run() - */ - // or just do that: rizla.DefaultDisableProgramRerunOutput = true // we don't want the banner to be shown after the first run - rizla.Run(programPath) + // run with the filepath.Walk method instead of file signals because + // some (not the majority) users' editors override the operating system's file signals + rizla.RunWith(rizla.WatcherFromFlag("-walk")) } diff --git a/middleware/README.md b/middleware/README.md index 4825c19d..c5ececdb 100644 --- a/middleware/README.md +++ b/middleware/README.md @@ -56,6 +56,18 @@ app.Get("/", indexHandler) ## Convert `http.Handler` to `iris.Handler` using the `iris.ToHandler` +```go +// ToHandler converts different type styles of handlers that you +// used to use (usually with third-party net/http middleware) to an iris.HandlerFunc. +// +// Supported types: +// - .ToHandler(h http.Handler) +// - .ToHandler(func(w http.ResponseWriter, r *http.Request)) +// - .ToHandler(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)) +func ToHandler(handler interface{}) HandlerFunc +``` + + ```go app := iris.New()