From 9bce4e846af66420c6892617083d4310dc4bbb12 Mon Sep 17 00:00:00 2001 From: Gerasimos Maropoulos Date: Tue, 11 Oct 2016 22:35:12 +0300 Subject: [PATCH] Update to 4.5.2 --- HISTORY.md | 33 +++++++++++++++++++++++++++++++++ README.md | 6 +++--- configuration.go | 22 ++++++++++++++++++---- context.go | 15 +++++++++++++++ http.go | 33 ++++++++++++++++++++++++++------- http_test.go | 24 ++++++++++++++++++++++++ iris.go | 3 ++- 7 files changed, 121 insertions(+), 15 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 49e33e00..6c988cab 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,39 @@ **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`. + +## 4.5.1 -> 4.5.2 + +- **Feature request**: I never though that it will be easier for users to catch 405 instead of simple 404, I though that will make your life harder, but it's requested by the Community [here](https://github.com/kataras/iris/issues/469), so I did my duty. Enable firing Status Method Not Allowed (405) with a simple configuration field: `iris.Config.FireMethodNotAllowed=true` or `iris.Set(iris.OptionFireMethodNotAllowed(true))` or `app := iris.New(iris.Configuration{FireMethodNotAllowed:true})`, a test example: + +```go + +func TestMuxFireMethodNotAllowed(t *testing.T) { + + iris.Config.FireMethodNotAllowed = true // enable catching 405 errors + + h := func(ctx *iris.Context) { + ctx.Write("%s", ctx.MethodString()) + } + + Iris.OnError(iris.StatusMethodNotAllowed, func(ctx *iris.Context) { + ctx.Write("Hello from my custom 405 page") + }) + + iris.Get("/mypath", h) + iris.Put("/mypath", h) + + e := iris.Tester(t) + + e.GET("/mypath").Expect().Status(StatusOK).Body().Equal("GET") + e.PUT("/mypath").Expect().Status(StatusOK).Body().Equal("PUT") + // this should fail with 405 and catch by the custom http error + + e.POST("/mypath").Expect().Status(StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page") + iris.Close() +} +``` + ## 4.5.0 -> 4.5.1 - **NEW**: `PreBuild` plugin type, raises before `.Build`. Used by third-party plugins to register any runtime routes or make any changes to the iris main configuration, example of this usage is the [OAuth/OAuth2 Plugin](https://github.com/iris-contrib/plugin/tree/master/oauth). diff --git a/README.md b/README.md index 7bcacc37..f9678011 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@
-Releases +Releases Examples @@ -871,7 +871,7 @@ I recommend writing your API tests using this new library, [httpexpect](https:// Versioning ------------ -Current: **v4.5.1** +Current: **v4.5.2** > Iris is an active project @@ -907,7 +907,7 @@ This project is licensed under the [MIT License](LICENSE), Copyright (c) 2016 Ge [Travis]: http://travis-ci.org/kataras/iris [License Widget]: https://img.shields.io/badge/license-MIT%20%20License%20-E91E63.svg?style=flat-square [License]: https://github.com/kataras/iris/blob/master/LICENSE -[Release Widget]: https://img.shields.io/badge/release-4.5.1%20-blue.svg?style=flat-square +[Release Widget]: https://img.shields.io/badge/release-4.5.2%20-blue.svg?style=flat-square [Release]: https://github.com/kataras/iris/releases [Chat Widget]: https://img.shields.io/badge/community-chat%20-00BCD4.svg?style=flat-square [Chat]: https://kataras.rocket.chat/channel/iris diff --git a/configuration.go b/configuration.go index c644f445..e4dd9d29 100644 --- a/configuration.go +++ b/configuration.go @@ -1,15 +1,16 @@ package iris import ( - "github.com/imdario/mergo" - "github.com/kataras/go-options" - "github.com/kataras/go-sessions" - "github.com/valyala/fasthttp" "io" "net/url" "os" "strconv" "time" + + "github.com/imdario/mergo" + "github.com/kataras/go-options" + "github.com/kataras/go-sessions" + "github.com/valyala/fasthttp" ) type ( @@ -160,6 +161,10 @@ type Configuration struct { // Default is false DisablePathEscape bool + // FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and fires the 405 error instead of 404 + // Default is false + FireMethodNotAllowed bool + // DisableBanner outputs the iris banner at startup // // Default is false @@ -381,6 +386,14 @@ var ( } } + // FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and fires the 405 error instead of 404 + // Default is false + OptionFireMethodNotAllowed = func(val bool) OptionSet { + return func(c *Configuration) { + c.FireMethodNotAllowed = val + } + } + // OptionDisableBanner outputs the iris banner at startup // // Default is false @@ -523,6 +536,7 @@ func DefaultConfiguration() Configuration { CheckForUpdatesSync: false, DisablePathCorrection: DefaultDisablePathCorrection, DisablePathEscape: DefaultDisablePathEscape, + FireMethodNotAllowed: false, DisableBanner: false, LoggerOut: DefaultLoggerOut, LoggerPreffix: DefaultLoggerPreffix, diff --git a/context.go b/context.go index f7f3c76b..5b12c6af 100644 --- a/context.go +++ b/context.go @@ -147,16 +147,31 @@ func (ctx *Context) GetHandlerName() string { /* Request */ // Param returns the string representation of the key's path named parameter's value +// +// Return value should be never stored directly, instead store it to a local variable, +// for example +// instead of: context.Session().Set("name", ctx.Param("user")) +// do this: username:= ctx.Param("user");ctx.Session().Set("name", username) func (ctx *Context) Param(key string) string { return ctx.Params.Get(key) } // ParamInt returns the int representation of the key's path named parameter's value +// +// Return value should be never stored directly, instead store it to a local variable, +// for example +// instead of: context.Session().Set("age", ctx.Param("age")) +// do this: age:= ctx.Param("age");ctx.Session().Set("age", age) func (ctx *Context) ParamInt(key string) (int, error) { return strconv.Atoi(ctx.Param(key)) } // ParamInt64 returns the int64 representation of the key's path named parameter's value +// +// Return value should be never stored directly, instead store it to a local variable, +// for example +// instead of: context.Session().Set("ms", ctx.ParamInt64("ms")) +// do this: ms:= ctx.ParamInt64("ms");ctx.Session().Set("ms", ms) func (ctx *Context) ParamInt64(key string) (int64, error) { return strconv.ParseInt(ctx.Param(key), 10, 64) } diff --git a/http.go b/http.go index a99e9b56..2ca8b645 100644 --- a/http.go +++ b/http.go @@ -949,18 +949,22 @@ type ( // if false then the /something it's not the same as /something/ // defaults to true correctPath bool - mu sync.Mutex + // if enabled then the router checks and fires an error for 405 http status method not allowed too if no method compatible method was found + // by default is false + fireMethodNotAllowed bool + mu sync.Mutex } ) func newServeMux(logger *log.Logger) *serveMux { mux := &serveMux{ - lookups: make([]*route, 0), - errorHandlers: make(map[int]Handler, 0), - hostname: DefaultServerHostname, // these are changing when the server is up - escapePath: !DefaultDisablePathEscape, - correctPath: !DefaultDisablePathCorrection, - logger: logger, + lookups: make([]*route, 0), + errorHandlers: make(map[int]Handler, 0), + hostname: DefaultServerHostname, // these are changing when the server is up + escapePath: !DefaultDisablePathEscape, + correctPath: !DefaultDisablePathCorrection, + fireMethodNotAllowed: false, + logger: logger, } return mux @@ -978,6 +982,10 @@ func (mux *serveMux) setCorrectPath(b bool) { mux.correctPath = b } +func (mux *serveMux) setFireMethodNotAllowed(b bool) { + mux.fireMethodNotAllowed = b +} + // registerError registers a handler to a http status func (mux *serveMux) registerError(statusCode int, handler Handler) { mux.mu.Lock() @@ -1183,6 +1191,17 @@ func (mux *serveMux) BuildHandler() HandlerFunc { // not found break } + // https://github.com/kataras/iris/issues/469 + if mux.fireMethodNotAllowed { + for i := range mux.garden { + tree := mux.garden[i] + if !methodEqual(context.Method(), tree.method) { + continue + } + } + mux.fireError(StatusMethodNotAllowed, context) + return + } mux.fireError(StatusNotFound, context) } } diff --git a/http_test.go b/http_test.go index 9f801898..1127b1fb 100644 --- a/http_test.go +++ b/http_test.go @@ -665,3 +665,27 @@ func TestMuxCustomHandler(t *testing.T) { expectedData4.DynamicPathParameter = param4 e.GET("/custom_handler_2/" + param4).Expect().Status(StatusOK).JSON().Equal(expectedData4) } + +func TestMuxFireMethodNotAllowed(t *testing.T) { + initDefault() + Default.Config.FireMethodNotAllowed = true + h := func(ctx *Context) { + ctx.Write("%s", ctx.MethodString()) + } + + Default.OnError(StatusMethodNotAllowed, func(ctx *Context) { + ctx.Write("Hello from my custom 405 page") + }) + + Get("/mypath", h) + Put("/mypath", h) + + e := Tester(t) + + e.GET("/mypath").Expect().Status(StatusOK).Body().Equal("GET") + e.PUT("/mypath").Expect().Status(StatusOK).Body().Equal("PUT") + // this should fail with 405 and catch by the custom http error + + e.POST("/mypath").Expect().Status(StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page") + Close() +} diff --git a/iris.go b/iris.go index cb47d355..28c98338 100644 --- a/iris.go +++ b/iris.go @@ -79,7 +79,7 @@ import ( const ( // Version is the current version of the Iris web framework - Version = "4.5.1" + Version = "4.5.2" banner = ` _____ _ |_ _| (_) @@ -353,6 +353,7 @@ func (s *Framework) Build() { // prepare the mux runtime fields again, for any case s.mux.setCorrectPath(!s.Config.DisablePathCorrection) s.mux.setEscapePath(!s.Config.DisablePathEscape) + s.mux.setFireMethodNotAllowed(s.Config.FireMethodNotAllowed) // prepare the server's handler, we do that check because iris supports // custom routers (you can take the routes registed by iris using iris.Lookups function)