mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
Offling routing and prioritize others before static handlers https://github.com/kataras/iris/issues/585
Read HISTORY.md
This commit is contained in:
parent
c91a1e6628
commit
3489ba3365
86
HISTORY.md
86
HISTORY.md
|
@ -8,10 +8,14 @@
|
|||
|
||||
- Discussion: https://github.com/kataras/iris/issues/585
|
||||
- Test: https://github.com/kataras/iris/blob/master/http_test.go#L735
|
||||
- Example: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
- Example 1: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
- Example 2, SPA: https://github.com/iris-contrib/examples/tree/master/spa_2_using_offline_routing
|
||||
|
||||
**What?**
|
||||
|
||||
|
||||
- Give priority to an API path inside a Static route
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
|
@ -21,38 +25,57 @@ import (
|
|||
|
||||
func main() {
|
||||
|
||||
iris.None("/api/user/:userid", func(ctx *iris.Context) {
|
||||
usersAPI := iris.None("/api/users/:userid", func(ctx *iris.Context) {
|
||||
ctx.Writef("user with id: %s", ctx.Param("userid"))
|
||||
})("api.users.id")
|
||||
|
||||
iris.StaticWeb("/", "./www", usersAPI)
|
||||
|
||||
//
|
||||
// START THE SERVER
|
||||
//
|
||||
iris.Listen("localhost:8080")
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
- Play with(very advanced usage, used by big companies): enable(online) or disable(offline) routes at runtime with one line of code.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// You can find the Route by iris.Lookup("theRouteName")
|
||||
// you can set a route name as: myRoute := iris.Get("/mypath", handler)("theRouteName")
|
||||
// that will set a name to the route and returns its iris.Route instance for further usage.
|
||||
api := iris.None("/api/users/:userid", func(ctx *iris.Context) {
|
||||
userid := ctx.Param("userid")
|
||||
ctx.Writef("user with id: %s", userid)
|
||||
})("user.api")
|
||||
})("users.api")
|
||||
|
||||
// change the "user.api" state from offline to online and online to offline
|
||||
// change the "users.api" state from offline to online and online to offline
|
||||
iris.Get("/change", func(ctx *iris.Context) {
|
||||
routeName := "user.api"
|
||||
if iris.Lookup(routeName).IsOnline() {
|
||||
if api.IsOnline() {
|
||||
// set to offline
|
||||
iris.SetRouteOffline(routeName)
|
||||
iris.SetRouteOffline(api)
|
||||
} else {
|
||||
// set to online if it was not online(so it was offline)
|
||||
iris.SetRouteOnline(routeName, iris.MethodGet)
|
||||
iris.SetRouteOnline(api, iris.MethodGet)
|
||||
}
|
||||
})
|
||||
|
||||
// iris.Get("/execute/:routename", func(ctx *iris.Context) {
|
||||
// routeName := ctx.Param("routename")
|
||||
// userAPICtx := ctx.ExecuteRoute(routeName)
|
||||
// if userAPICtx == nil {
|
||||
// ctx.Writef("Route with name: %s didnt' found or couldn't be validate with this request path!", routeName)
|
||||
// }
|
||||
// })
|
||||
|
||||
iris.Get("/execute", func(ctx *iris.Context) {
|
||||
routeName := "user.api"
|
||||
// change the path in order to be catcable from the ExecuteRoute
|
||||
// ctx.Request.URL.Path = "/api/user/42"
|
||||
// ctx.ExecRoute(routeName)
|
||||
// ctx.Request.URL.Path = "/api/users/42"
|
||||
// ctx.ExecRoute(iris.Route)
|
||||
// or:
|
||||
ctx.ExecRouteAgainst(routeName, "/api/user/42")
|
||||
ctx.ExecRouteAgainst(api, "/api/users/42")
|
||||
})
|
||||
|
||||
iris.Get("/", func(ctx *iris.Context) {
|
||||
|
@ -63,11 +86,11 @@ func main() {
|
|||
// START THE SERVER
|
||||
//
|
||||
// STEPS:
|
||||
// 1. navigate to http://localhost:8080/user/api/42
|
||||
// 1. navigate to http://localhost:8080/api/users/42
|
||||
// you should get 404 error
|
||||
// 2. now, navigate to http://localhost:8080/change
|
||||
// you should see a blank page
|
||||
// 3. now, navigate to http://localhost:8080/user/api/42
|
||||
// 3. now, navigate to http://localhost:8080/api/users/42
|
||||
// you should see the page working, NO 404 error
|
||||
// go back to the http://localhost:8080/change
|
||||
// you should get 404 error again
|
||||
|
@ -78,6 +101,25 @@ func main() {
|
|||
|
||||
```
|
||||
|
||||
- New built'n Middleware: `iris.Prioritize(route)` in order to give priority to a route inside other handler (used internally on StaticWeb's builder)
|
||||
|
||||
```go
|
||||
usersAPI := iris.None("/api/users/:userid", func(ctx *iris.Context) {
|
||||
ctx.Writef("user with id: %s", ctx.Param("userid"))
|
||||
})("api.users.id") // we need to call empty ("") in order to get its iris.Route instance
|
||||
// or ("the name of the route")
|
||||
// which later on can be found with iris.Lookup("the name of the route")
|
||||
|
||||
static := iris.StaticHandler("/", "./www", false, false)
|
||||
// manually give a priority to the usersAPI, if not found then continue to the static handler
|
||||
iris.Get("/*file", iris.Prioritize(usersAPI), static)
|
||||
|
||||
iris.Get("/*file", static)
|
||||
|
||||
iris.Listen(":8080")
|
||||
|
||||
```
|
||||
|
||||
## 6.0.9 -> 6.1.0
|
||||
|
||||
- Fix a not found error when serving static files through custom subdomain, this should work again: `iris.Party("mysubdomain.").StaticWeb("/", "./static")`
|
||||
|
|
54
context.go
54
context.go
|
@ -177,11 +177,15 @@ func (ctx *Context) GetHandlerName() string {
|
|||
return runtime.FuncForPC(reflect.ValueOf(ctx.Middleware[len(ctx.Middleware)-1]).Pointer()).Name()
|
||||
}
|
||||
|
||||
// ExecRoute calls any route by its name (mostly "offline" route) like it was requested by the user, but it is not.
|
||||
// ExecRoute calls any route (mostly "offline" route) like it was requested by the user, but it is not.
|
||||
// Offline means that the route is registered to the iris and have all features that a normal route has
|
||||
// BUT it isn't available by browsing, its handlers executed only when other handler's context call them
|
||||
// it can validate paths, has sessions, path parameters and all.
|
||||
//
|
||||
// You can find the Route by iris.Lookup("theRouteName")
|
||||
// you can set a route name as: myRoute := iris.Get("/mypath", handler)("theRouteName")
|
||||
// that will set a name to the route and returns its iris.Route instance for further usage.
|
||||
//
|
||||
// It doesn't changes the global state, if a route was "offline" it remains offline.
|
||||
//
|
||||
// see ExecRouteAgainst(routeName, againstRequestPath string),
|
||||
|
@ -189,16 +193,20 @@ func (ctx *Context) GetHandlerName() string {
|
|||
// For more details look: https://github.com/kataras/iris/issues/585
|
||||
//
|
||||
// Example: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
func (ctx *Context) ExecRoute(routeName string) *Context {
|
||||
return ctx.ExecRouteAgainst(routeName, ctx.Path())
|
||||
func (ctx *Context) ExecRoute(r Route) *Context {
|
||||
return ctx.ExecRouteAgainst(r, ctx.Path())
|
||||
}
|
||||
|
||||
// ExecRouteAgainst calls any route by its name (mostly "offline" route) against a 'virtually' request path
|
||||
// ExecRouteAgainst calls any iris.Route against a 'virtually' request path
|
||||
// like it was requested by the user, but it is not.
|
||||
// Offline means that the route is registered to the iris and have all features that a normal route has
|
||||
// BUT it isn't available by browsing, its handlers executed only when other handler's context call them
|
||||
// it can validate paths, has sessions, path parameters and all.
|
||||
//
|
||||
// You can find the Route by iris.Lookup("theRouteName")
|
||||
// you can set a route name as: myRoute := iris.Get("/mypath", handler)("theRouteName")
|
||||
// that will set a name to the route and returns its iris.Route instance for further usage.
|
||||
//
|
||||
// It doesn't changes the global state, if a route was "offline" it remains offline.
|
||||
//
|
||||
// see ExecRoute(routeName),
|
||||
|
@ -206,9 +214,7 @@ func (ctx *Context) ExecRoute(routeName string) *Context {
|
|||
// For more details look: https://github.com/kataras/iris/issues/585
|
||||
//
|
||||
// Example: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
func (ctx *Context) ExecRouteAgainst(routeName string, againstRequestPath string) *Context {
|
||||
|
||||
r := ctx.framework.Lookup(routeName)
|
||||
func (ctx *Context) ExecRouteAgainst(r Route, againstRequestPath string) *Context {
|
||||
if r != nil {
|
||||
context := &(*ctx)
|
||||
context.Middleware = context.Middleware[0:0]
|
||||
|
@ -220,10 +226,42 @@ func (ctx *Context) ExecRouteAgainst(routeName string, againstRequestPath string
|
|||
return context
|
||||
}
|
||||
}
|
||||
// if failed return nil in order to this fail to be catchable
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prioritize is a middleware which executes a route against this path
|
||||
// when the request's Path has a prefix of the route's STATIC PART
|
||||
// is not executing ExecRoute to determinate if it's valid, for performance reasons
|
||||
// if this function is not enough for you and you want to test more than one parameterized path
|
||||
// then use the: if c := ExecRoute(r); c == nil { /* move to the next, the route is not valid */ }
|
||||
//
|
||||
// You can find the Route by iris.Lookup("theRouteName")
|
||||
// you can set a route name as: myRoute := iris.Get("/mypath", handler)("theRouteName")
|
||||
// that will set a name to the route and returns its iris.Route instance for further usage.
|
||||
//
|
||||
// if the route found then it executes that and don't continue to the next handler
|
||||
// if not found then continue to the next handler
|
||||
func Prioritize(r Route) HandlerFunc {
|
||||
if r != nil {
|
||||
return func(ctx *Context) {
|
||||
reqPath := ctx.Path()
|
||||
if strings.HasPrefix(reqPath, r.StaticPath()) {
|
||||
newctx := ctx.ExecRouteAgainst(r, reqPath)
|
||||
if newctx == nil { // route not found.
|
||||
ctx.EmitError(StatusNotFound)
|
||||
}
|
||||
return
|
||||
}
|
||||
// execute the next handler if no prefix
|
||||
// here look, the only error we catch is the 404,
|
||||
// we can't go ctx.Next() and believe that the next handler will manage the error
|
||||
// because it will not, we are not on the router.
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
return func(ctx *Context) { ctx.Next() }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------------
|
||||
// -----------------------------Request URL, Method, IP & Headers getters---------------
|
||||
|
|
32
http.go
32
http.go
|
@ -698,8 +698,16 @@ type (
|
|||
Subdomain() string
|
||||
// Method returns the http method
|
||||
Method() string
|
||||
// SetMethod sets the route's method
|
||||
// requires re-build of the iris.Router
|
||||
SetMethod(string)
|
||||
|
||||
// Path returns the path
|
||||
Path() string
|
||||
|
||||
// staticPath returns the static part of the path
|
||||
StaticPath() string
|
||||
|
||||
// SetPath changes/sets the path for this route
|
||||
SetPath(string)
|
||||
// Middleware returns the slice of Handler([]Handler) registered to this route
|
||||
|
@ -716,6 +724,7 @@ type (
|
|||
subdomain string
|
||||
method string
|
||||
path string
|
||||
staticPath string
|
||||
middleware Middleware
|
||||
formattedPath string
|
||||
formattedParts int
|
||||
|
@ -740,6 +749,7 @@ var _ Route = &route{}
|
|||
func newRoute(method string, subdomain string, path string, middleware Middleware) *route {
|
||||
r := &route{name: path + subdomain, method: method, subdomain: subdomain, path: path, middleware: middleware}
|
||||
r.formatPath()
|
||||
r.calculateStaticPath()
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -773,8 +783,20 @@ func (r *route) formatPath() {
|
|||
r.formattedPath = tempPath
|
||||
}
|
||||
|
||||
func (r *route) setName(newName string) {
|
||||
func (r *route) calculateStaticPath() {
|
||||
for i := 0; i < len(r.path); i++ {
|
||||
if r.path[i] == matchEverythingByte || r.path[i] == parameterStartByte {
|
||||
r.staticPath = r.path[0 : i-1] // stop at the first dynamic path symbol and set the static path to its [0:previous]
|
||||
return
|
||||
}
|
||||
}
|
||||
// not a dynamic symbol found, set its static path to its path.
|
||||
r.staticPath = r.path
|
||||
}
|
||||
|
||||
func (r *route) setName(newName string) Route {
|
||||
r.name = newName
|
||||
return r
|
||||
}
|
||||
|
||||
func (r route) Name() string {
|
||||
|
@ -789,10 +811,18 @@ func (r route) Method() string {
|
|||
return r.method
|
||||
}
|
||||
|
||||
func (r *route) SetMethod(method string) {
|
||||
r.method = method
|
||||
}
|
||||
|
||||
func (r route) Path() string {
|
||||
return r.path
|
||||
}
|
||||
|
||||
func (r route) StaticPath() string {
|
||||
return r.staticPath
|
||||
}
|
||||
|
||||
func (r *route) SetPath(s string) {
|
||||
r.path = s
|
||||
}
|
||||
|
|
14
http_test.go
14
http_test.go
|
@ -734,36 +734,34 @@ func TestRedirectHTTPS(t *testing.T) {
|
|||
|
||||
func TestRouteStateSimple(t *testing.T) {
|
||||
iris.ResetDefault()
|
||||
// here
|
||||
offlineRouteName := "user.api"
|
||||
offlineRoutePath := "/api/user/:userid"
|
||||
offlineRouteRequestedTestPath := "/api/user/42"
|
||||
offlineBody := "user with id: 42"
|
||||
|
||||
iris.None(offlineRoutePath, func(ctx *iris.Context) {
|
||||
offlineRoute := iris.None(offlineRoutePath, func(ctx *iris.Context) {
|
||||
userid := ctx.Param("userid")
|
||||
if userid != "42" {
|
||||
// we are expecting userid 42 always in this test so
|
||||
t.Fatalf("what happened? expected userid to be 42 but got %s", userid)
|
||||
}
|
||||
ctx.Writef(offlineBody)
|
||||
})(offlineRouteName)
|
||||
})("api.users") // or an empty (), required, in order to get the Route instance.
|
||||
|
||||
// change the "user.api" state from offline to online and online to offline
|
||||
iris.Get("/change", func(ctx *iris.Context) {
|
||||
// here
|
||||
if iris.Lookup(offlineRouteName).IsOnline() {
|
||||
if offlineRoute.IsOnline() {
|
||||
// set to offline
|
||||
iris.SetRouteOffline(offlineRouteName)
|
||||
iris.SetRouteOffline(offlineRoute)
|
||||
} else {
|
||||
// set to online if it was not online(so it was offline)
|
||||
iris.SetRouteOnline(offlineRouteName, iris.MethodGet)
|
||||
iris.SetRouteOnline(offlineRoute, iris.MethodGet)
|
||||
}
|
||||
})
|
||||
|
||||
iris.Get("/execute", func(ctx *iris.Context) {
|
||||
// here
|
||||
ctx.ExecRouteAgainst(offlineRouteName, "/api/user/42")
|
||||
ctx.ExecRouteAgainst(offlineRoute, "/api/user/42")
|
||||
})
|
||||
|
||||
hello := "Hello from index"
|
||||
|
|
82
iris.go
82
iris.go
|
@ -171,9 +171,9 @@ type (
|
|||
|
||||
Lookup(routeName string) Route
|
||||
Lookups() []Route
|
||||
SetRouteOnline(routeName string, HTTPMethod string) bool
|
||||
SetRouteOffline(routeName string) bool
|
||||
ChangeRouteState(routeName string, HTTPMethod string) bool
|
||||
SetRouteOnline(r Route, HTTPMethod string) bool
|
||||
SetRouteOffline(r Route) bool
|
||||
ChangeRouteState(r Route, HTTPMethod string) bool
|
||||
|
||||
Path(routeName string, optionalPathParameters ...interface{}) (routePath string)
|
||||
URL(routeName string, optionalPathParameters ...interface{}) (routeURL string)
|
||||
|
@ -219,8 +219,8 @@ type (
|
|||
StaticEmbedded(reqRelativePath string, contentType string, assets func(string) ([]byte, error), assetsNames func() []string) RouteNameFunc
|
||||
Favicon(systemFilePath string, optionalReqRelativePath ...string) RouteNameFunc
|
||||
// static file system
|
||||
StaticHandler(reqRelativePath string, systemPath string, showList bool, enableGzip bool) HandlerFunc
|
||||
StaticWeb(reqRelativePath string, systemPath string) RouteNameFunc
|
||||
StaticHandler(reqRelativePath string, systemPath string, showList bool, enableGzip bool, exceptRoutes ...Route) HandlerFunc
|
||||
StaticWeb(reqRelativePath string, systemPath string, exceptRoutes ...Route) RouteNameFunc
|
||||
|
||||
// party layout for template engines
|
||||
Layout(layoutTemplateFileName string) MuxAPI
|
||||
|
@ -231,7 +231,12 @@ type (
|
|||
}
|
||||
|
||||
// RouteNameFunc the func returns from the MuxAPi's methods, optionally sets the name of the Route (*route)
|
||||
RouteNameFunc func(customRouteName string)
|
||||
//
|
||||
// You can find the Route by iris.Lookup("theRouteName")
|
||||
// you can set a route name as: myRoute := iris.Get("/mypath", handler)("theRouteName")
|
||||
// that will set a name to the route and returns its iris.Route instance for further usage.
|
||||
//
|
||||
RouteNameFunc func(customRouteName string) Route
|
||||
)
|
||||
|
||||
// Framework is our God |\| Google.Search('Greek mythology Iris')
|
||||
|
@ -1060,8 +1065,8 @@ func (s *Framework) Lookups() (routes []Route) {
|
|||
// For more details look: https://github.com/kataras/iris/issues/585
|
||||
//
|
||||
// Example: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
func SetRouteOnline(routeName string, HTTPMethod string) bool {
|
||||
return Default.SetRouteOnline(routeName, HTTPMethod)
|
||||
func SetRouteOnline(r Route, HTTPMethod string) bool {
|
||||
return Default.SetRouteOnline(r, HTTPMethod)
|
||||
}
|
||||
|
||||
// SetRouteOffline sets the state of the route to "offline" and re-builds the router
|
||||
|
@ -1073,8 +1078,8 @@ func SetRouteOnline(routeName string, HTTPMethod string) bool {
|
|||
// For more details look: https://github.com/kataras/iris/issues/585
|
||||
//
|
||||
// Example: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
func SetRouteOffline(routeName string) bool {
|
||||
return Default.SetRouteOffline(routeName)
|
||||
func SetRouteOffline(r Route) bool {
|
||||
return Default.SetRouteOffline(r)
|
||||
}
|
||||
|
||||
// ChangeRouteState changes the state of the route.
|
||||
|
@ -1089,23 +1094,23 @@ func SetRouteOffline(routeName string) bool {
|
|||
// For more details look: https://github.com/kataras/iris/issues/585
|
||||
//
|
||||
// Example: https://github.com/iris-contrib/examples/tree/master/route_state
|
||||
func ChangeRouteState(routeName string, HTTPMethod string) bool {
|
||||
return Default.ChangeRouteState(routeName, HTTPMethod)
|
||||
func ChangeRouteState(r Route, HTTPMethod string) bool {
|
||||
return Default.ChangeRouteState(r, HTTPMethod)
|
||||
}
|
||||
|
||||
// SetRouteOnline sets the state of the route to "online" with a specific http method
|
||||
// it re-builds the router
|
||||
//
|
||||
// returns true if state was actually changed
|
||||
func (s *Framework) SetRouteOnline(routeName string, HTTPMethod string) bool {
|
||||
return s.ChangeRouteState(routeName, HTTPMethod)
|
||||
func (s *Framework) SetRouteOnline(r Route, HTTPMethod string) bool {
|
||||
return s.ChangeRouteState(r, HTTPMethod)
|
||||
}
|
||||
|
||||
// SetRouteOffline sets the state of the route to "offline" and re-builds the router
|
||||
//
|
||||
// returns true if state was actually changed
|
||||
func (s *Framework) SetRouteOffline(routeName string) bool {
|
||||
return s.ChangeRouteState(routeName, MethodNone)
|
||||
func (s *Framework) SetRouteOffline(r Route) bool {
|
||||
return s.ChangeRouteState(r, MethodNone)
|
||||
}
|
||||
|
||||
// ChangeRouteState changes the state of the route.
|
||||
|
@ -1114,15 +1119,14 @@ func (s *Framework) SetRouteOffline(routeName string) bool {
|
|||
// it re-builds the router
|
||||
//
|
||||
// returns true if state was actually changed
|
||||
func (s *Framework) ChangeRouteState(routeName string, HTTPMethod string) bool {
|
||||
r := s.mux.lookup(routeName)
|
||||
nonSpecificMethod := len(HTTPMethod) == 0
|
||||
func (s *Framework) ChangeRouteState(r Route, HTTPMethod string) bool {
|
||||
if r != nil {
|
||||
if r.method != HTTPMethod {
|
||||
nonSpecificMethod := len(HTTPMethod) == 0
|
||||
if r.Method() != HTTPMethod {
|
||||
if nonSpecificMethod {
|
||||
r.method = MethodGet // if no method given, then do it for "GET" only
|
||||
r.SetMethod(MethodGet) // if no method given, then do it for "GET" only
|
||||
} else {
|
||||
r.method = HTTPMethod
|
||||
r.SetMethod(HTTPMethod)
|
||||
}
|
||||
// re-build the router/main handler
|
||||
s.Router = ToNativeHandler(s, s.mux.BuildHandler())
|
||||
|
@ -2064,32 +2068,13 @@ func (api *muxAPI) Favicon(favPath string, requestPath ...string) RouteNameFunc
|
|||
return api.registerResourceRoute(reqPath, h)
|
||||
}
|
||||
|
||||
// StripPrefix returns a handler that serves HTTP requests
|
||||
// by removing the given prefix from the request URL's Path
|
||||
// and invoking the handler h. StripPrefix handles a
|
||||
// request for a path that doesn't begin with prefix by
|
||||
// replying with an HTTP 404 not found error.
|
||||
func StripPrefix(prefix string, h HandlerFunc) HandlerFunc {
|
||||
if prefix == "" {
|
||||
return h
|
||||
}
|
||||
return func(ctx *Context) {
|
||||
if p := strings.TrimPrefix(ctx.Request.URL.Path, prefix); len(p) < len(ctx.Request.URL.Path) {
|
||||
ctx.Request.URL.Path = p
|
||||
h(ctx)
|
||||
} else {
|
||||
ctx.NotFound()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StaticHandler returns a new Handler which serves static files
|
||||
func StaticHandler(reqPath string, systemPath string, showList bool, enableGzip bool) HandlerFunc {
|
||||
return Default.StaticHandler(reqPath, systemPath, showList, enableGzip)
|
||||
}
|
||||
|
||||
// StaticHandler returns a new Handler which serves static files
|
||||
func (api *muxAPI) StaticHandler(reqPath string, systemPath string, showList bool, enableGzip bool) HandlerFunc {
|
||||
func (api *muxAPI) StaticHandler(reqPath string, systemPath string, showList bool, enableGzip bool, exceptRoutes ...Route) HandlerFunc {
|
||||
// here we separate the path from the subdomain (if any), we care only for the path
|
||||
// fixes a bug when serving static files via a subdomain
|
||||
fullpath := api.relativePath + reqPath
|
||||
|
@ -2102,6 +2087,7 @@ func (api *muxAPI) StaticHandler(reqPath string, systemPath string, showList boo
|
|||
Path(path).
|
||||
Listing(showList).
|
||||
Gzip(enableGzip).
|
||||
Except(exceptRoutes...).
|
||||
Build()
|
||||
|
||||
managedStaticHandler := func(ctx *Context) {
|
||||
|
@ -2124,6 +2110,8 @@ func (api *muxAPI) StaticHandler(reqPath string, systemPath string, showList boo
|
|||
//
|
||||
// first parameter: the route path
|
||||
// second parameter: the system directory
|
||||
// third OPTIONAL parameter: the exception routes
|
||||
// (= give priority to these routes instead of the static handler)
|
||||
// for more options look iris.StaticHandler.
|
||||
//
|
||||
// iris.StaticWeb("/static", "./static")
|
||||
|
@ -2133,8 +2121,8 @@ func (api *muxAPI) StaticHandler(reqPath string, systemPath string, showList boo
|
|||
// "index.html".
|
||||
//
|
||||
// StaticWeb calls the StaticHandler(reqPath, systemPath, listingDirectories: false, gzip: false ).
|
||||
func StaticWeb(reqPath string, systemPath string) RouteNameFunc {
|
||||
return Default.StaticWeb(reqPath, systemPath)
|
||||
func StaticWeb(reqPath string, systemPath string, exceptRoutes ...Route) RouteNameFunc {
|
||||
return Default.StaticWeb(reqPath, systemPath, exceptRoutes...)
|
||||
}
|
||||
|
||||
// StaticWeb returns a handler that serves HTTP requests
|
||||
|
@ -2142,6 +2130,8 @@ func StaticWeb(reqPath string, systemPath string) RouteNameFunc {
|
|||
//
|
||||
// first parameter: the route path
|
||||
// second parameter: the system directory
|
||||
// third OPTIONAL parameter: the exception routes
|
||||
// (= give priority to these routes instead of the static handler)
|
||||
// for more options look iris.StaticHandler.
|
||||
//
|
||||
// iris.StaticWeb("/static", "./static")
|
||||
|
@ -2151,8 +2141,8 @@ func StaticWeb(reqPath string, systemPath string) RouteNameFunc {
|
|||
// "index.html".
|
||||
//
|
||||
// StaticWeb calls the StaticHandler(reqPath, systemPath, listingDirectories: false, gzip: false ).
|
||||
func (api *muxAPI) StaticWeb(reqPath string, systemPath string) RouteNameFunc {
|
||||
h := api.StaticHandler(reqPath, systemPath, false, false)
|
||||
func (api *muxAPI) StaticWeb(reqPath string, systemPath string, exceptRoutes ...Route) RouteNameFunc {
|
||||
h := api.StaticHandler(reqPath, systemPath, false, false, exceptRoutes...)
|
||||
routePath := validateWildcard(reqPath, "file")
|
||||
return api.registerResourceRoute(routePath, h)
|
||||
}
|
||||
|
|
45
webfs.go
45
webfs.go
|
@ -14,6 +14,7 @@ type StaticHandlerBuilder interface {
|
|||
Gzip(enable bool) StaticHandlerBuilder
|
||||
Listing(listDirectoriesOnOff bool) StaticHandlerBuilder
|
||||
StripPath(yesNo bool) StaticHandlerBuilder
|
||||
Except(r ...Route) StaticHandlerBuilder
|
||||
Build() HandlerFunc
|
||||
}
|
||||
|
||||
|
@ -27,6 +28,7 @@ type webfs struct {
|
|||
// these are init on the Build() call
|
||||
filesystem http.FileSystem
|
||||
once sync.Once
|
||||
exceptions []Route
|
||||
handler HandlerFunc
|
||||
}
|
||||
|
||||
|
@ -88,6 +90,13 @@ func (w *webfs) StripPath(yesNo bool) StaticHandlerBuilder {
|
|||
return w
|
||||
}
|
||||
|
||||
// Except add a route exception,
|
||||
// gives priority to that Route over the static handler.
|
||||
func (w *webfs) Except(r ...Route) StaticHandlerBuilder {
|
||||
w.exceptions = append(w.exceptions, r...)
|
||||
return w
|
||||
}
|
||||
|
||||
type (
|
||||
noListFile struct {
|
||||
http.File
|
||||
|
@ -130,7 +139,7 @@ func (w *webfs) Build() HandlerFunc {
|
|||
fsHandler = http.StripPrefix(prefix, fileserver)
|
||||
}
|
||||
|
||||
w.handler = func(ctx *Context) {
|
||||
h := func(ctx *Context) {
|
||||
writer := ctx.ResponseWriter
|
||||
|
||||
if w.gzip && ctx.clientAllowsGzip() {
|
||||
|
@ -143,7 +152,41 @@ func (w *webfs) Build() HandlerFunc {
|
|||
|
||||
fsHandler.ServeHTTP(writer, ctx.Request)
|
||||
}
|
||||
|
||||
if len(w.exceptions) > 0 {
|
||||
middleware := make(Middleware, len(w.exceptions)+1)
|
||||
for i := range w.exceptions {
|
||||
middleware[i] = Prioritize(w.exceptions[i])
|
||||
}
|
||||
middleware[len(w.exceptions)] = HandlerFunc(h)
|
||||
|
||||
w.handler = func(ctx *Context) {
|
||||
ctx.Middleware = append(middleware, ctx.Middleware...)
|
||||
ctx.Do()
|
||||
}
|
||||
} else {
|
||||
w.handler = h
|
||||
}
|
||||
})
|
||||
|
||||
return w.handler
|
||||
}
|
||||
|
||||
// StripPrefix returns a handler that serves HTTP requests
|
||||
// by removing the given prefix from the request URL's Path
|
||||
// and invoking the handler h. StripPrefix handles a
|
||||
// request for a path that doesn't begin with prefix by
|
||||
// replying with an HTTP 404 not found error.
|
||||
func StripPrefix(prefix string, h HandlerFunc) HandlerFunc {
|
||||
if prefix == "" {
|
||||
return h
|
||||
}
|
||||
return func(ctx *Context) {
|
||||
if p := strings.TrimPrefix(ctx.Request.URL.Path, prefix); len(p) < len(ctx.Request.URL.Path) {
|
||||
ctx.Request.URL.Path = p
|
||||
h(ctx)
|
||||
} else {
|
||||
ctx.NotFound()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user