mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
Implement the Status Method Not Allowed for gorilla mux too and add some tests
Former-commit-id: b157bacfa15567b8c98f959f3359e025fdf1b205
This commit is contained in:
parent
6fca78d12a
commit
b25d99870e
|
@ -34,6 +34,15 @@ import (
|
||||||
|
|
||||||
const dynamicSymbol = '{'
|
const dynamicSymbol = '{'
|
||||||
|
|
||||||
|
func staticPath(path string) string {
|
||||||
|
i := strings.IndexByte(path, dynamicSymbol)
|
||||||
|
if i > -1 {
|
||||||
|
return path[0:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
// New returns a new gorilla mux router which can be plugged inside iris.
|
// New returns a new gorilla mux router which can be plugged inside iris.
|
||||||
// This is magic.
|
// This is magic.
|
||||||
func New() iris.Policies {
|
func New() iris.Policies {
|
||||||
|
@ -46,14 +55,7 @@ func New() iris.Policies {
|
||||||
}},
|
}},
|
||||||
RouterReversionPolicy: iris.RouterReversionPolicy{
|
RouterReversionPolicy: iris.RouterReversionPolicy{
|
||||||
// path normalization done on iris' side
|
// path normalization done on iris' side
|
||||||
StaticPath: func(path string) string {
|
StaticPath: staticPath,
|
||||||
i := strings.IndexByte(path, dynamicSymbol)
|
|
||||||
if i > -1 {
|
|
||||||
return path[0:i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
},
|
|
||||||
WildcardPath: func(requestPath string, paramName string) string {
|
WildcardPath: func(requestPath string, paramName string) string {
|
||||||
return requestPath + "/{" + paramName + ":.*}"
|
return requestPath + "/{" + paramName + ":.*}"
|
||||||
},
|
},
|
||||||
|
@ -94,10 +96,48 @@ func New() iris.Policies {
|
||||||
|
|
||||||
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := context.Acquire(w, r)
|
ctx := context.Acquire(w, r)
|
||||||
// to catch custom 404 not found http errors may registered by user
|
// gorilla mux doesn't supports fire method not allowed like iris
|
||||||
ctx.EmitError(iris.StatusNotFound)
|
// so this is my hack to support it:
|
||||||
|
if ctx.Framework().Config.FireMethodNotAllowed {
|
||||||
|
stopVisitor := false
|
||||||
|
repo.Visit(func(route iris.RouteInfo) {
|
||||||
|
if stopVisitor {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// this is not going to work 100% for all routes especially the coblex
|
||||||
|
// but this is the best solution, to check via static path, subdomain and cors to find the 'correct' route to
|
||||||
|
// compare its method in order to implement the status method not allowed in gorilla mux which doesn't support it
|
||||||
|
// and if I edit its internal implementation it will be complicated for new releases to be updated.
|
||||||
|
p := staticPath(route.Path())
|
||||||
|
if route.Subdomain() == "" || route.Subdomain() == ctx.Subdomain() {
|
||||||
|
if p == ctx.Path() {
|
||||||
|
// we don't care about this route because it has cors and this method is options
|
||||||
|
// or its method is equal with the requests but the router didn't select this route
|
||||||
|
// that means that the dynamic path didn't match, so we skip it.
|
||||||
|
if (route.HasCors() && ctx.Method() == iris.MethodOptions) || ctx.Method() == route.Method() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Method() != route.Method() {
|
||||||
|
// RCF rfc2616 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
|
// The response MUST include an Allow header containing a list of valid methods for the requested resource.
|
||||||
|
ctx.SetHeader("Allow", route.Method())
|
||||||
|
ctx.EmitError(iris.StatusMethodNotAllowed)
|
||||||
|
stopVisitor = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// to catch custom 404 not found http errors may registered by user
|
||||||
|
ctx.EmitError(iris.StatusNotFound)
|
||||||
|
}
|
||||||
context.Release(ctx)
|
context.Release(ctx)
|
||||||
})
|
})
|
||||||
|
|
||||||
return router
|
return router
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,12 +702,17 @@ func (mux *serveMux) buildHandler(pool iris.ContextPool) http.Handler {
|
||||||
}
|
}
|
||||||
// https://github.com/kataras/iris/issues/469
|
// https://github.com/kataras/iris/issues/469
|
||||||
if context.Framework().Config.FireMethodNotAllowed {
|
if context.Framework().Config.FireMethodNotAllowed {
|
||||||
|
var methodAllowed string
|
||||||
for i := range mux.garden {
|
for i := range mux.garden {
|
||||||
tree := mux.garden[i]
|
tree := mux.garden[i]
|
||||||
|
methodAllowed = tree.method // keep track of the allowed method of the last checked tree
|
||||||
if !mux.methodEqual(context.Method(), tree.method) {
|
if !mux.methodEqual(context.Method(), tree.method) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// RCF rfc2616 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
|
// The response MUST include an Allow header containing a list of valid methods for the requested resource.
|
||||||
|
context.SetHeader("Allow", methodAllowed)
|
||||||
context.EmitError(iris.StatusMethodNotAllowed)
|
context.EmitError(iris.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
61
handler_test.go
Normal file
61
handler_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// black-box
|
||||||
|
package iris_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/kataras/iris.v6"
|
||||||
|
"gopkg.in/kataras/iris.v6/httptest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const testCustomHandlerParamName = "myparam"
|
||||||
|
|
||||||
|
type myTestHandlerData struct {
|
||||||
|
Sysname string // this will be the same for all requests
|
||||||
|
Version int // this will be the same for all requests
|
||||||
|
URLParameter string // this will be different for each request
|
||||||
|
}
|
||||||
|
|
||||||
|
type myTestCustomHandler struct {
|
||||||
|
data myTestHandlerData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *myTestCustomHandler) Serve(ctx *iris.Context) {
|
||||||
|
data := &m.data
|
||||||
|
data.URLParameter = ctx.URLParam(testCustomHandlerParamName)
|
||||||
|
ctx.JSON(iris.StatusOK, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomHandler(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(newTestNativeRouter())
|
||||||
|
|
||||||
|
myData := myTestHandlerData{
|
||||||
|
Sysname: "Redhat",
|
||||||
|
Version: 1,
|
||||||
|
}
|
||||||
|
app.Handle("GET", "/custom_handler_1", &myTestCustomHandler{myData})
|
||||||
|
app.Handle("GET", "/custom_handler_2", &myTestCustomHandler{myData})
|
||||||
|
|
||||||
|
e := httptest.New(app, t, httptest.Debug(true))
|
||||||
|
// two times per testRoute
|
||||||
|
param1 := "thisimyparam1"
|
||||||
|
expectedData1 := myData
|
||||||
|
expectedData1.URLParameter = param1
|
||||||
|
e.GET("/custom_handler_1/").WithQuery(testCustomHandlerParamName, param1).Expect().Status(iris.StatusOK).JSON().Equal(expectedData1)
|
||||||
|
|
||||||
|
param2 := "thisimyparam2"
|
||||||
|
expectedData2 := myData
|
||||||
|
expectedData2.URLParameter = param2
|
||||||
|
e.GET("/custom_handler_1/").WithQuery(testCustomHandlerParamName, param2).Expect().Status(iris.StatusOK).JSON().Equal(expectedData2)
|
||||||
|
|
||||||
|
param3 := "thisimyparam3"
|
||||||
|
expectedData3 := myData
|
||||||
|
expectedData3.URLParameter = param3
|
||||||
|
e.GET("/custom_handler_2/").WithQuery(testCustomHandlerParamName, param3).Expect().Status(iris.StatusOK).JSON().Equal(expectedData3)
|
||||||
|
|
||||||
|
param4 := "thisimyparam4"
|
||||||
|
expectedData4 := myData
|
||||||
|
expectedData4.URLParameter = param4
|
||||||
|
e.GET("/custom_handler_2/").WithQuery(testCustomHandlerParamName, param4).Expect().Status(iris.StatusOK).JSON().Equal(expectedData4)
|
||||||
|
}
|
|
@ -255,3 +255,27 @@ func TestGorillaMuxRouteURLPath(t *testing.T) {
|
||||||
t.Fatalf("gorillamux' reverse routing 'URLPath' error: expected %s but got %s", expected, got)
|
t.Fatalf("gorillamux' reverse routing 'URLPath' error: expected %s but got %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGorillaMuxFireMethodNotAllowed(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(gorillamux.New())
|
||||||
|
app.Config.FireMethodNotAllowed = true
|
||||||
|
h := func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.Method())
|
||||||
|
}
|
||||||
|
|
||||||
|
app.OnError(iris.StatusMethodNotAllowed, func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString("Hello from my custom 405 page")
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/mypath", h)
|
||||||
|
app.Put("/mypath", h)
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/mypath").Expect().Status(iris.StatusOK).Body().Equal("GET")
|
||||||
|
e.PUT("/mypath").Expect().Status(iris.StatusOK).Body().Equal("PUT")
|
||||||
|
// this should fail with 405 and catch by the custom http error
|
||||||
|
|
||||||
|
e.POST("/mypath").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page")
|
||||||
|
}
|
||||||
|
|
|
@ -268,3 +268,27 @@ func TestHTTPRouterRouteURLPath(t *testing.T) {
|
||||||
t.Fatalf("httprouter's reverse routing 'URLPath' error: expected %s but got %s", expected, got)
|
t.Fatalf("httprouter's reverse routing 'URLPath' error: expected %s but got %s", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTTPRouterFireMethodNotAllowed(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(httprouter.New())
|
||||||
|
app.Config.FireMethodNotAllowed = true
|
||||||
|
h := func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString(ctx.Method())
|
||||||
|
}
|
||||||
|
|
||||||
|
app.OnError(iris.StatusMethodNotAllowed, func(ctx *iris.Context) {
|
||||||
|
ctx.WriteString("Hello from my custom 405 page")
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/mypath", h)
|
||||||
|
app.Put("/mypath", h)
|
||||||
|
|
||||||
|
e := httptest.New(app, t)
|
||||||
|
|
||||||
|
e.GET("/mypath").Expect().Status(iris.StatusOK).Body().Equal("GET")
|
||||||
|
e.PUT("/mypath").Expect().Status(iris.StatusOK).Body().Equal("PUT")
|
||||||
|
// this should fail with 405 and catch by the custom http error
|
||||||
|
|
||||||
|
e.POST("/mypath").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user