mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
init of v11.2.0: add context#FullRequestURI and NewConditionalHandler
As requested at: https://github.com/kataras/iris/issues/1167 and https://github.com/kataras/iris/issues/1170 Former-commit-id: 781c92f444b3e362011be886b32cf88f89998589
This commit is contained in:
parent
571ef59adf
commit
3fcc70b891
49
_examples/routing/conditional-chain/main.go
Normal file
49
_examples/routing/conditional-chain/main.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
v1 := app.Party("/api/v1")
|
||||||
|
|
||||||
|
myFilter := func(ctx iris.Context) bool {
|
||||||
|
// don't do that on production, use session or/and database calls and etc.
|
||||||
|
ok, _ := ctx.URLParamBool("admin")
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
onlyWhenFilter1 := func(ctx iris.Context) {
|
||||||
|
ctx.Application().Logger().Infof("admin: %s", ctx.Params())
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
onlyWhenFilter2 := func(ctx iris.Context) {
|
||||||
|
// You can always use the per-request storage
|
||||||
|
// to perform actions like this ofc.
|
||||||
|
//
|
||||||
|
// this handler: ctx.Values().Set("is_admin", true)
|
||||||
|
// next handler: isAdmin := ctx.Values().GetBoolDefault("is_admin", false)
|
||||||
|
//
|
||||||
|
// but, let's simplify it:
|
||||||
|
ctx.HTML("<h1>Hello Admin</h1><br>")
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HERE:
|
||||||
|
// It can be registered anywhere, as a middleware.
|
||||||
|
// It will fire the `onlyWhenFilter1` and `onlyWhenFilter2` as middlewares (with ctx.Next())
|
||||||
|
// if myFilter pass otherwise it will just continue the handler chain with ctx.Next() by ignoring
|
||||||
|
// the `onlyWhenFilter1` and `onlyWhenFilter2`.
|
||||||
|
myMiddleware := iris.NewConditionalHandler(myFilter, onlyWhenFilter1, onlyWhenFilter2)
|
||||||
|
|
||||||
|
v1UsersRouter := v1.Party("/users", myMiddleware)
|
||||||
|
v1UsersRouter.Get("/", func(ctx iris.Context) {
|
||||||
|
ctx.HTML("requested: <b>/api/v1/users</b>")
|
||||||
|
})
|
||||||
|
|
||||||
|
// http://localhost:8080/api/v1/users
|
||||||
|
// http://localhost:8080/api/v1/users?admin=true
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
|
@ -292,7 +292,6 @@ type Context interface {
|
||||||
// RequestPath returns the full request path,
|
// RequestPath returns the full request path,
|
||||||
// based on the 'escape'.
|
// based on the 'escape'.
|
||||||
RequestPath(escape bool) string
|
RequestPath(escape bool) string
|
||||||
|
|
||||||
// Host returns the host part of the current url.
|
// Host returns the host part of the current url.
|
||||||
Host() string
|
Host() string
|
||||||
// Subdomain returns the subdomain of this request, if any.
|
// Subdomain returns the subdomain of this request, if any.
|
||||||
|
@ -300,6 +299,9 @@ type Context interface {
|
||||||
Subdomain() (subdomain string)
|
Subdomain() (subdomain string)
|
||||||
// IsWWW returns true if the current subdomain (if any) is www.
|
// IsWWW returns true if the current subdomain (if any) is www.
|
||||||
IsWWW() bool
|
IsWWW() bool
|
||||||
|
// FullRqeuestURI returns the full URI,
|
||||||
|
// including the scheme, the host and the relative requested path/resource.
|
||||||
|
FullRequestURI() string
|
||||||
// RemoteAddr tries to parse and return the real client's request IP.
|
// RemoteAddr tries to parse and return the real client's request IP.
|
||||||
//
|
//
|
||||||
// Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
|
// Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
|
||||||
|
@ -1465,11 +1467,11 @@ func (ctx *context) Host() string {
|
||||||
|
|
||||||
// GetHost returns the host part of the current URI.
|
// GetHost returns the host part of the current URI.
|
||||||
func GetHost(r *http.Request) string {
|
func GetHost(r *http.Request) string {
|
||||||
h := r.URL.Host
|
if host := r.Host; host != "" {
|
||||||
if h == "" {
|
return host
|
||||||
h = r.Host
|
|
||||||
}
|
}
|
||||||
return h
|
|
||||||
|
return r.URL.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subdomain returns the subdomain of this request, if any.
|
// Subdomain returns the subdomain of this request, if any.
|
||||||
|
@ -1502,6 +1504,24 @@ func (ctx *context) IsWWW() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FullRqeuestURI returns the full URI,
|
||||||
|
// including the scheme, the host and the relative requested path/resource.
|
||||||
|
func (ctx *context) FullRequestURI() string {
|
||||||
|
scheme := ctx.request.URL.Scheme
|
||||||
|
if scheme == "" {
|
||||||
|
if ctx.request.TLS != nil {
|
||||||
|
scheme = "https:"
|
||||||
|
} else {
|
||||||
|
scheme = "http:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host := ctx.Host()
|
||||||
|
path := ctx.Path()
|
||||||
|
|
||||||
|
return scheme + "//" + host + path
|
||||||
|
}
|
||||||
|
|
||||||
const xForwardedForHeaderKey = "X-Forwarded-For"
|
const xForwardedForHeaderKey = "X-Forwarded-For"
|
||||||
|
|
||||||
// RemoteAddr tries to parse and return the real client's request IP.
|
// RemoteAddr tries to parse and return the real client's request IP.
|
||||||
|
|
|
@ -34,3 +34,55 @@ func HandlerName(h Handler) string {
|
||||||
// return fmt.Sprintf("%s:%d", l, n)
|
// return fmt.Sprintf("%s:%d", l, n)
|
||||||
return runtime.FuncForPC(pc).Name()
|
return runtime.FuncForPC(pc).Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter is just a type of func(Handler) bool which reports whether an action must be performed
|
||||||
|
// based on the incoming request.
|
||||||
|
//
|
||||||
|
// See `NewConditionalHandler` for more.
|
||||||
|
type Filter func(Context) bool
|
||||||
|
|
||||||
|
// NewConditionalHandler returns a single Handler which can be registered
|
||||||
|
// as a middleware.
|
||||||
|
// Filter is just a type of Handler which returns a boolean.
|
||||||
|
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
||||||
|
// to the next handler of the chain. Those "handlers" are registed to the per-request context.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// It checks the "filter" and if passed then
|
||||||
|
// it, correctly, executes the "handlers".
|
||||||
|
//
|
||||||
|
// If passed, this function makes sure that the Context's information
|
||||||
|
// about its per-request handler chain based on the new "handlers" is always updated.
|
||||||
|
//
|
||||||
|
// If not passed, then simply the Next handler(if any) is executed and "handlers" are ignored.
|
||||||
|
//
|
||||||
|
// Example can be found at: _examples/routing/conditional-chain.
|
||||||
|
func NewConditionalHandler(filter Filter, handlers ...Handler) Handler {
|
||||||
|
return func(ctx Context) {
|
||||||
|
if filter(ctx) {
|
||||||
|
// Note that we don't want just to fire the incoming handlers, we must make sure
|
||||||
|
// that it won't break any further handler chain
|
||||||
|
// information that may be required for the next handlers.
|
||||||
|
//
|
||||||
|
// The below code makes sure that this conditional handler does not break
|
||||||
|
// the ability that iris provides to its end-devs
|
||||||
|
// to check and modify the per-request handlers chain at runtime.
|
||||||
|
currIdx := ctx.HandlerIndex(-1)
|
||||||
|
currHandlers := ctx.Handlers()
|
||||||
|
if currIdx == len(currHandlers)-1 {
|
||||||
|
// if this is the last handler of the chain
|
||||||
|
// just add to the last the new handlers and call Next to fire those.
|
||||||
|
ctx.AddHandler(handlers...)
|
||||||
|
ctx.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// otherwise insert the new handlers in the middle of the current executed chain and the next chain.
|
||||||
|
newHandlers := append(currHandlers[:currIdx], append(handlers, currHandlers[currIdx+1:]...)...)
|
||||||
|
ctx.SetHandlers(newHandlers)
|
||||||
|
ctx.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// if not pass, then just execute the next.
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
6
go19.go
6
go19.go
|
@ -42,6 +42,12 @@ type (
|
||||||
// If Handler panics, the server (the caller of Handler) assumes that the effect of the panic was isolated to the active request.
|
// If Handler panics, the server (the caller of Handler) assumes that the effect of the panic was isolated to the active request.
|
||||||
// It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.
|
// It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.
|
||||||
Handler = context.Handler
|
Handler = context.Handler
|
||||||
|
// Filter is just a type of func(Handler) bool which reports whether an action must be performed
|
||||||
|
// based on the incoming request.
|
||||||
|
//
|
||||||
|
// See `NewConditionalHandler` for more.
|
||||||
|
// An alias for the `context/Filter`.
|
||||||
|
Filter = context.Filter
|
||||||
// A Map is a shortcut of the map[string]interface{}.
|
// A Map is a shortcut of the map[string]interface{}.
|
||||||
Map = context.Map
|
Map = context.Map
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/iris-contrib/httpexpect"
|
|
||||||
"github.com/kataras/iris"
|
"github.com/kataras/iris"
|
||||||
|
|
||||||
|
"github.com/iris-contrib/httpexpect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
18
iris.go
18
iris.go
|
@ -341,6 +341,24 @@ var (
|
||||||
//
|
//
|
||||||
// A shortcut for the `context#LimitRequestBodySize`.
|
// A shortcut for the `context#LimitRequestBodySize`.
|
||||||
LimitRequestBodySize = context.LimitRequestBodySize
|
LimitRequestBodySize = context.LimitRequestBodySize
|
||||||
|
// NewConditionalHandler returns a single Handler which can be registered
|
||||||
|
// as a middleware.
|
||||||
|
// Filter is just a type of Handler which returns a boolean.
|
||||||
|
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
||||||
|
// to the next handler of the chain. Those "handlers" are registed to the per-request context.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// It checks the "filter" and if passed then
|
||||||
|
// it, correctly, executes the "handlers".
|
||||||
|
//
|
||||||
|
// If passed, this function makes sure that the Context's information
|
||||||
|
// about its per-request handler chain based on the new "handlers" is always updated.
|
||||||
|
//
|
||||||
|
// If not passed, then simply the Next handler(if any) is executed and "handlers" are ignored.
|
||||||
|
// Example can be found at: _examples/routing/conditional-chain.
|
||||||
|
//
|
||||||
|
// A shortcut for the `context#NewConditionalHandler`.
|
||||||
|
NewConditionalHandler = context.NewConditionalHandler
|
||||||
// StaticEmbeddedHandler returns a Handler which can serve
|
// StaticEmbeddedHandler returns a Handler which can serve
|
||||||
// embedded into executable files.
|
// embedded into executable files.
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue
Block a user