mirror of
https://github.com/kataras/iris.git
synced 2025-02-09 02:34:55 +01:00
implement #1536 with (SetRegisterRule(iris.RouteOverlap))
Former-commit-id: 2b5523ff3e2aab60dd83faa3c520b16a34916fbe
This commit is contained in:
parent
78a45163e3
commit
ed5964716b
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
|
@ -17,10 +17,10 @@ jobs:
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-go-
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
- name: Set up Go 1.13
|
- name: Set up Go 1.14
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.13
|
go-version: 1.14
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
|
|
|
@ -26,6 +26,11 @@ func main() {
|
||||||
|
|
||||||
userRouter := app.Party("/user")
|
userRouter := app.Party("/user")
|
||||||
{
|
{
|
||||||
|
// Use that in order to be able to register a route twice,
|
||||||
|
// last one will be executed if the previous route's handler(s) stopped and the response can be reset-ed.
|
||||||
|
// See core/router/route_register_rule_test.go#TestRegisterRuleOverlap.
|
||||||
|
userRouter.SetRegisterRule(iris.RouteOverlap)
|
||||||
|
|
||||||
// Initialize a new MVC application on top of the "userRouter".
|
// Initialize a new MVC application on top of the "userRouter".
|
||||||
userApp := mvc.New(userRouter)
|
userApp := mvc.New(userRouter)
|
||||||
// Register Dependencies.
|
// Register Dependencies.
|
||||||
|
@ -34,6 +39,7 @@ func main() {
|
||||||
// Register Controllers.
|
// Register Controllers.
|
||||||
userApp.Handle(new(MeController))
|
userApp.Handle(new(MeController))
|
||||||
userApp.Handle(new(UserController))
|
userApp.Handle(new(UserController))
|
||||||
|
userApp.Handle(new(UnauthenticatedUserController))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open a client, e.g. Postman and visit the below endpoints.
|
// Open a client, e.g. Postman and visit the below endpoints.
|
||||||
|
@ -61,6 +67,15 @@ func authDependency(ctx iris.Context, session *sessions.Session) Authenticated {
|
||||||
return Authenticated(userID)
|
return Authenticated(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnauthenticatedUserController serves the "public" Unauthorized User API.
|
||||||
|
type UnauthenticatedUserController struct{}
|
||||||
|
|
||||||
|
// GetMe registers a route that will be executed when authentication is not passed
|
||||||
|
// (see UserController.GetMe) too.
|
||||||
|
func (c *UnauthenticatedUserController) GetMe() string {
|
||||||
|
return `custom action to redirect on authentication page`
|
||||||
|
}
|
||||||
|
|
||||||
// UserController serves the "public" User API.
|
// UserController serves the "public" User API.
|
||||||
type UserController struct {
|
type UserController struct {
|
||||||
Session *sessions.Session
|
Session *sessions.Session
|
||||||
|
|
|
@ -169,7 +169,6 @@ type Context interface {
|
||||||
SetHandlers(Handlers)
|
SetHandlers(Handlers)
|
||||||
// Handlers keeps tracking of the current handlers.
|
// Handlers keeps tracking of the current handlers.
|
||||||
Handlers() Handlers
|
Handlers() Handlers
|
||||||
|
|
||||||
// HandlerIndex sets the current index of the
|
// HandlerIndex sets the current index of the
|
||||||
// current context's handlers chain.
|
// current context's handlers chain.
|
||||||
// If n < 0 or the current handlers length is 0 then it just returns the
|
// If n < 0 or the current handlers length is 0 then it just returns the
|
||||||
|
|
|
@ -192,6 +192,7 @@ func (w *GzipResponseWriter) Body() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetBody resets the response body.
|
// ResetBody resets the response body.
|
||||||
|
// Implements the `ResponseWriterBodyReseter`.
|
||||||
func (w *GzipResponseWriter) ResetBody() {
|
func (w *GzipResponseWriter) ResetBody() {
|
||||||
w.chunks = w.chunks[0:0]
|
w.chunks = w.chunks[0:0]
|
||||||
}
|
}
|
||||||
|
@ -202,6 +203,26 @@ func (w *GzipResponseWriter) Disable() {
|
||||||
w.disabled = true
|
w.disabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset disables the gzip content writer, clears headers, sets the status code to 200
|
||||||
|
// and clears the cached body.
|
||||||
|
//
|
||||||
|
// Implements the `ResponseWriterReseter`.
|
||||||
|
func (w *GzipResponseWriter) Reset() bool {
|
||||||
|
// disable gzip content writer.
|
||||||
|
w.Disable()
|
||||||
|
// clear headers.
|
||||||
|
h := w.ResponseWriter.Header()
|
||||||
|
for k := range h {
|
||||||
|
h[k] = nil
|
||||||
|
}
|
||||||
|
// restore status code.
|
||||||
|
w.WriteHeader(defaultStatusCode)
|
||||||
|
// reset body.
|
||||||
|
w.ResetBody()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// FlushResponse validates the response headers in order to be compatible with the gzip written data
|
// FlushResponse validates the response headers in order to be compatible with the gzip written data
|
||||||
// and writes the data to the underline ResponseWriter.
|
// and writes the data to the underline ResponseWriter.
|
||||||
func (w *GzipResponseWriter) FlushResponse() {
|
func (w *GzipResponseWriter) FlushResponse() {
|
||||||
|
|
|
@ -139,11 +139,15 @@ func (w *ResponseRecorder) ClearHeaders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset resets the response body, headers and the status code header.
|
// Reset clears headers, sets the status code to 200
|
||||||
func (w *ResponseRecorder) Reset() {
|
// and clears the cached body.
|
||||||
|
//
|
||||||
|
// Implements the `ResponseWriterReseter`.
|
||||||
|
func (w *ResponseRecorder) Reset() bool {
|
||||||
w.ClearHeaders()
|
w.ClearHeaders()
|
||||||
w.WriteHeader(defaultStatusCode)
|
w.WriteHeader(defaultStatusCode)
|
||||||
w.ResetBody()
|
w.ResetBody()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlushResponse the full body, headers and status code to the underline response writer
|
// FlushResponse the full body, headers and status code to the underline response writer
|
||||||
|
|
|
@ -105,6 +105,32 @@ type ResponseWriter interface {
|
||||||
CloseNotifier() (http.CloseNotifier, bool)
|
CloseNotifier() (http.CloseNotifier, bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResponseWriterBodyReseter can be implemented by
|
||||||
|
// response writers that supports response body overriding
|
||||||
|
// (e.g. recorder and compressed).
|
||||||
|
type ResponseWriterBodyReseter interface {
|
||||||
|
// ResetBody should reset the body and reports back if it could reset successfully.
|
||||||
|
ResetBody()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseWriterDisabler can be implemented
|
||||||
|
// by response writers that can be disabled and restored to their previous state
|
||||||
|
// (e.g. compressed).
|
||||||
|
type ResponseWriterDisabler interface {
|
||||||
|
// Disable should disable this type of response writer and fallback to the default one.
|
||||||
|
Disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseWriterReseter can be implemented
|
||||||
|
// by response writers that can clear the whole response
|
||||||
|
// so a new handler can write into this from the beginning.
|
||||||
|
// E.g. recorder, compressed (full) and common writer (status code and headers).
|
||||||
|
type ResponseWriterReseter interface {
|
||||||
|
// Reset should reset the whole response and reports
|
||||||
|
// whether it could reset successfully.
|
||||||
|
Reset() bool
|
||||||
|
}
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
// | Response Writer Implementation |
|
// | Response Writer Implementation |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
@ -167,6 +193,25 @@ func (w *responseWriter) EndResponse() {
|
||||||
releaseResponseWriter(w)
|
releaseResponseWriter(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset clears headers, sets the status code to 200
|
||||||
|
// and clears the cached body.
|
||||||
|
//
|
||||||
|
// Implements the `ResponseWriterReseter`.
|
||||||
|
func (w *responseWriter) Reset() bool {
|
||||||
|
if w.written > 0 {
|
||||||
|
return false // if already written we can't reset this type of response writer.
|
||||||
|
}
|
||||||
|
|
||||||
|
h := w.Header()
|
||||||
|
for k := range h {
|
||||||
|
h[k] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
w.written = NoWritten
|
||||||
|
w.statusCode = defaultStatusCode
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// SetWritten sets manually a value for written, it can be
|
// SetWritten sets manually a value for written, it can be
|
||||||
// NoWritten(-1) or StatusCodeWritten(0), > 0 means body length which is useless here.
|
// NoWritten(-1) or StatusCodeWritten(0), > 0 means body length which is useless here.
|
||||||
func (w *responseWriter) SetWritten(n int) {
|
func (w *responseWriter) SetWritten(n int) {
|
||||||
|
|
|
@ -18,21 +18,19 @@ func FromStd(handler interface{}) context.Handler {
|
||||||
case context.Handler:
|
case context.Handler:
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// it's already a iris handler
|
// it's already an Iris Handler
|
||||||
//
|
//
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
case http.Handler:
|
case http.Handler:
|
||||||
|
{
|
||||||
//
|
//
|
||||||
// handlerFunc.ServeHTTP(w,r)
|
// handlerFunc.ServeHTTP(w,r)
|
||||||
//
|
//
|
||||||
{
|
|
||||||
return func(ctx context.Context) {
|
return func(ctx context.Context) {
|
||||||
h.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
|
h.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case func(http.ResponseWriter, *http.Request):
|
case func(http.ResponseWriter, *http.Request):
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
@ -40,7 +38,6 @@ func FromStd(handler interface{}) context.Handler {
|
||||||
//
|
//
|
||||||
return FromStd(http.HandlerFunc(h))
|
return FromStd(http.HandlerFunc(h))
|
||||||
}
|
}
|
||||||
|
|
||||||
case func(http.ResponseWriter, *http.Request, http.HandlerFunc):
|
case func(http.ResponseWriter, *http.Request, http.HandlerFunc):
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
@ -48,7 +45,6 @@ func FromStd(handler interface{}) context.Handler {
|
||||||
//
|
//
|
||||||
return FromStdWithNext(h)
|
return FromStdWithNext(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
@ -62,7 +58,6 @@ func FromStd(handler interface{}) context.Handler {
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
It seems to be a %T points to: %v`, handler, handler))
|
It seems to be a %T points to: %v`, handler, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +65,10 @@ func FromStd(handler interface{}) context.Handler {
|
||||||
// compatible context.Handler wrapper.
|
// compatible context.Handler wrapper.
|
||||||
func FromStdWithNext(h func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)) context.Handler {
|
func FromStdWithNext(h func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)) context.Handler {
|
||||||
return func(ctx context.Context) {
|
return func(ctx context.Context) {
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
next := func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx.ResetRequest(r)
|
ctx.ResetRequest(r)
|
||||||
ctx.Next()
|
ctx.Next()
|
||||||
})
|
}
|
||||||
|
|
||||||
h(ctx.ResponseWriter(), ctx.Request(), next)
|
h(ctx.ResponseWriter(), ctx.Request(), next)
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,9 @@ func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route,
|
||||||
return r, nil
|
return r, nil
|
||||||
} else if rule == RouteError {
|
} else if rule == RouteError {
|
||||||
return nil, fmt.Errorf("new route: %s conflicts with an already registered one: %s route", route.String(), r.String())
|
return nil, fmt.Errorf("new route: %s conflicts with an already registered one: %s route", route.String(), r.String())
|
||||||
|
} else if rule == RouteOverlap {
|
||||||
|
overlapRoute(r, route)
|
||||||
|
return route, nil
|
||||||
} else {
|
} else {
|
||||||
// replace existing with the latest one, the default behavior.
|
// replace existing with the latest one, the default behavior.
|
||||||
repo.routes = append(repo.routes[:i], repo.routes[i+1:]...)
|
repo.routes = append(repo.routes[:i], repo.routes[i+1:]...)
|
||||||
|
@ -113,6 +116,38 @@ func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route,
|
||||||
return route, nil
|
return route, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var defaultOverlapFilter = func(ctx context.Context) bool {
|
||||||
|
if ctx.IsStopped() {
|
||||||
|
// It's stopped and the response can be overriden by a new handler.
|
||||||
|
rs, ok := ctx.ResponseWriter().(context.ResponseWriterReseter)
|
||||||
|
return ok && rs.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's not stopped, all OK no need to execute the alternative route.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func overlapRoute(r *Route, next *Route) {
|
||||||
|
next.BuildHandlers()
|
||||||
|
nextHandlers := next.Handlers[0:]
|
||||||
|
|
||||||
|
decisionHandler := func(ctx context.Context) {
|
||||||
|
ctx.Next()
|
||||||
|
|
||||||
|
if !defaultOverlapFilter(ctx) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetCurrentRoute(next.ReadOnly)
|
||||||
|
ctx.HandlerIndex(0)
|
||||||
|
ctx.Do(nextHandlers)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(@kataras): Any UseGlobal call will prepend to this, if they are
|
||||||
|
// in the same Party then it's expected, otherwise not.
|
||||||
|
r.beginHandlers = append(context.Handlers{decisionHandler}, r.beginHandlers...)
|
||||||
|
}
|
||||||
|
|
||||||
// APIBuilder the visible API for constructing the router
|
// APIBuilder the visible API for constructing the router
|
||||||
// and child routers.
|
// and child routers.
|
||||||
type APIBuilder struct {
|
type APIBuilder struct {
|
||||||
|
@ -261,10 +296,17 @@ const (
|
||||||
// RouteError log when a route already exists, shown after the `Build` state,
|
// RouteError log when a route already exists, shown after the `Build` state,
|
||||||
// server never starts.
|
// server never starts.
|
||||||
RouteError
|
RouteError
|
||||||
|
// RouteOverlap will overlap the new route to the previous one.
|
||||||
|
// If the route stopped and its response can be reset then the new route will be execute.
|
||||||
|
RouteOverlap
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetRegisterRule sets a `RouteRegisterRule` for this Party and its children.
|
// SetRegisterRule sets a `RouteRegisterRule` for this Party and its children.
|
||||||
// Available values are: RouteOverride (the default one), RouteSkip and RouteError.
|
// Available values are:
|
||||||
|
// * RouteOverride (the default one)
|
||||||
|
// * RouteSkip
|
||||||
|
// * RouteError
|
||||||
|
// * RouteOverlap.
|
||||||
func (api *APIBuilder) SetRegisterRule(rule RouteRegisterRule) Party {
|
func (api *APIBuilder) SetRegisterRule(rule RouteRegisterRule) Party {
|
||||||
api.routeRegisterRule = rule
|
api.routeRegisterRule = rule
|
||||||
return api
|
return api
|
||||||
|
|
|
@ -116,7 +116,11 @@ type Party interface {
|
||||||
// Example: https://github.com/kataras/iris/tree/master/_examples/mvc/middleware/without-ctx-next
|
// Example: https://github.com/kataras/iris/tree/master/_examples/mvc/middleware/without-ctx-next
|
||||||
SetExecutionRules(executionRules ExecutionRules) Party
|
SetExecutionRules(executionRules ExecutionRules) Party
|
||||||
// SetRegisterRule sets a `RouteRegisterRule` for this Party and its children.
|
// SetRegisterRule sets a `RouteRegisterRule` for this Party and its children.
|
||||||
// Available values are: RouteOverride (the default one), RouteSkip and RouteError.
|
// Available values are:
|
||||||
|
// * RouteOverride (the default one)
|
||||||
|
// * RouteSkip
|
||||||
|
// * RouteError
|
||||||
|
// * RouteOverlap.
|
||||||
SetRegisterRule(rule RouteRegisterRule) Party
|
SetRegisterRule(rule RouteRegisterRule) Party
|
||||||
|
|
||||||
// Handle registers a route to the server's router.
|
// Handle registers a route to the server's router.
|
||||||
|
|
|
@ -66,6 +66,9 @@ type Route struct {
|
||||||
|
|
||||||
// ReadOnly is the read-only structure of the Route.
|
// ReadOnly is the read-only structure of the Route.
|
||||||
ReadOnly context.RouteReadOnly
|
ReadOnly context.RouteReadOnly
|
||||||
|
|
||||||
|
// OnBuild runs right before BuildHandlers.
|
||||||
|
OnBuild func(r *Route)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRoute returns a new route based on its method,
|
// NewRoute returns a new route based on its method,
|
||||||
|
@ -186,6 +189,10 @@ func (r *Route) RestoreStatus() bool {
|
||||||
// at the `Application#Build` state. Do not call it manually, unless
|
// at the `Application#Build` state. Do not call it manually, unless
|
||||||
// you were defined your own request mux handler.
|
// you were defined your own request mux handler.
|
||||||
func (r *Route) BuildHandlers() {
|
func (r *Route) BuildHandlers() {
|
||||||
|
if r.OnBuild != nil {
|
||||||
|
r.OnBuild(r)
|
||||||
|
}
|
||||||
|
|
||||||
if len(r.beginHandlers) > 0 {
|
if len(r.beginHandlers) > 0 {
|
||||||
r.Handlers = append(r.beginHandlers, r.Handlers...)
|
r.Handlers = append(r.beginHandlers, r.Handlers...)
|
||||||
r.beginHandlers = r.beginHandlers[0:0]
|
r.beginHandlers = r.beginHandlers[0:0]
|
||||||
|
|
|
@ -58,3 +58,54 @@ func testRegisterRule(e *httptest.Expect, expectedGetBody string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRegisterRuleOverlap(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
// TODO(@kataras) the overlapping does not work per-party yet,
|
||||||
|
// it just checks compares from the total app's routes (which is the best possible action to do
|
||||||
|
// because MVC applications can be separated into different parties too?).
|
||||||
|
usersRouter := app.Party("/users")
|
||||||
|
usersRouter.SetRegisterRule(iris.RouteOverlap)
|
||||||
|
|
||||||
|
// second handler will be executed, status will be reset-ed as well,
|
||||||
|
// stop without data written.
|
||||||
|
usersRouter.Get("/", func(ctx iris.Context) {
|
||||||
|
ctx.StopWithStatus(iris.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
usersRouter.Get("/", func(ctx iris.Context) {
|
||||||
|
ctx.WriteString("data")
|
||||||
|
})
|
||||||
|
|
||||||
|
// first handler will be executed, no stop called.
|
||||||
|
usersRouter.Get("/p1", func(ctx iris.Context) {
|
||||||
|
ctx.StatusCode(iris.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
usersRouter.Get("/p1", func(ctx iris.Context) {
|
||||||
|
ctx.WriteString("not written")
|
||||||
|
})
|
||||||
|
|
||||||
|
// first handler will be executed, stop but with data sent on default writer
|
||||||
|
// (body sent cannot be reset-ed here).
|
||||||
|
usersRouter.Get("/p2", func(ctx iris.Context) {
|
||||||
|
ctx.StopWithText(iris.StatusUnauthorized, "no access")
|
||||||
|
})
|
||||||
|
usersRouter.Get("/p2", func(ctx iris.Context) {
|
||||||
|
ctx.WriteString("not written")
|
||||||
|
})
|
||||||
|
|
||||||
|
// second will be executed, response can be reset-ed on recording.
|
||||||
|
usersRouter.Get("/p3", func(ctx iris.Context) {
|
||||||
|
ctx.Record()
|
||||||
|
ctx.StopWithText(iris.StatusUnauthorized, "no access")
|
||||||
|
})
|
||||||
|
usersRouter.Get("/p3", func(ctx iris.Context) {
|
||||||
|
ctx.WriteString("p3 data")
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
|
e.GET("/users").Expect().Status(httptest.StatusOK).Body().Equal("data")
|
||||||
|
e.GET("/users/p1").Expect().Status(httptest.StatusUnauthorized).Body().Equal("Unauthorized")
|
||||||
|
e.GET("/users/p2").Expect().Status(httptest.StatusUnauthorized).Body().Equal("no access")
|
||||||
|
e.GET("/users/p3").Expect().Status(httptest.StatusOK).Body().Equal("p3 data")
|
||||||
|
}
|
||||||
|
|
2
doc.go
2
doc.go
|
@ -38,7 +38,7 @@ Source code and other details for the project are available at GitHub:
|
||||||
|
|
||||||
Current Version
|
Current Version
|
||||||
|
|
||||||
12.1.8
|
12.2.0
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
|
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -19,7 +19,7 @@ require (
|
||||||
github.com/iris-contrib/jade v1.1.4
|
github.com/iris-contrib/jade v1.1.4
|
||||||
github.com/iris-contrib/pongo2 v0.0.1
|
github.com/iris-contrib/pongo2 v0.0.1
|
||||||
github.com/iris-contrib/schema v0.0.1
|
github.com/iris-contrib/schema v0.0.1
|
||||||
github.com/json-iterator/go v1.1.9
|
github.com/json-iterator/go v1.1.10
|
||||||
github.com/kataras/golog v0.0.18
|
github.com/kataras/golog v0.0.18
|
||||||
github.com/kataras/neffos v0.0.16
|
github.com/kataras/neffos v0.0.16
|
||||||
github.com/kataras/pio v0.0.8
|
github.com/kataras/pio v0.0.8
|
||||||
|
@ -34,7 +34,7 @@ require (
|
||||||
github.com/vmihailenco/msgpack/v5 v5.0.0-alpha.2
|
github.com/vmihailenco/msgpack/v5 v5.0.0-alpha.2
|
||||||
go.etcd.io/bbolt v1.3.4
|
go.etcd.io/bbolt v1.3.4
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
|
||||||
gopkg.in/ini.v1 v1.57.0
|
gopkg.in/ini.v1 v1.57.0
|
||||||
|
|
3
iris.go
3
iris.go
|
@ -617,6 +617,9 @@ const (
|
||||||
// RouteError log when a route already exists, shown after the `Build` state,
|
// RouteError log when a route already exists, shown after the `Build` state,
|
||||||
// server never starts.
|
// server never starts.
|
||||||
RouteError = router.RouteError
|
RouteError = router.RouteError
|
||||||
|
// RouteOverlap will overlap the new route to the previous one.
|
||||||
|
// If the route stopped and its response can be reset then the new route will be execute.
|
||||||
|
RouteOverlap = router.RouteOverlap
|
||||||
)
|
)
|
||||||
|
|
||||||
// Contains the enum values of the `Context.GetReferrer()` method,
|
// Contains the enum values of the `Context.GetReferrer()` method,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user