diff --git a/_examples/examples/url-shortener/main.go b/_examples/examples/url-shortener/main.go
index 7ac86cf4..fea4291e 100644
--- a/_examples/examples/url-shortener/main.go
+++ b/_examples/examples/url-shortener/main.go
@@ -23,6 +23,18 @@ func main() {
// Serve static files (css)
app.StaticWeb("/static", "./static_files")
+ // other solution for both static files and urls in the root path(not recommended but it's here if you ever need it):
+ // fileserver := iris.StaticHandler("./static_files", false, false)
+ // app.Get("/*path", func(ctx *iris.Context) {
+ // fileserver.Serve(ctx)
+ // if ctx.StatusCode() >= 200 && ctx.StatusCode() < 300 {
+ // // then the file found and served correctly.
+ // } else {
+ // // otherwise check for urls....
+ // execShortURL(ctx, ctx.Param("path"))
+ // }
+ // })
+
var mu sync.Mutex
var urls = map[string]string{
"iris": "http://support.iris-go.com",
@@ -53,7 +65,7 @@ func main() {
execShortURL(ctx, ctx.Param("shortkey"))
})
- // for wildcard subdomain (yeah.. cool) http://dsaoj41u321dsa.localhost:8080
+ // for wildcard subdomain (yeah.. cool) http://dsaoj41u321dsa.localhost:8080
// Note:
// if you want subdomains (chrome doesn't works on localhost, so you have to define other hostname on app.Listen)
// app.Party("*.", func(ctx *iris.Context) {
diff --git a/adaptors/view/_examples/custom_renderer/main.go b/adaptors/view/_examples/custom_renderer/main.go
new file mode 100644
index 00000000..e9fdb28d
--- /dev/null
+++ b/adaptors/view/_examples/custom_renderer/main.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+ "io"
+
+ "gopkg.in/kataras/iris.v6"
+ "gopkg.in/kataras/iris.v6/adaptors/httprouter"
+)
+
+func main() {
+ app := iris.New()
+ // output startup banner and error logs on os.Stdout
+ app.Adapt(iris.DevLogger())
+ // set the router, you can choose gorillamux too
+ app.Adapt(httprouter.New())
+
+ // Custom Render Policy to override or create new content-type render
+ // i,e: "text/html" with a prefix,
+ // we will just write to the writer and return false
+ // to continue to the next contentType-matched renderer if any.
+ app.Adapt(iris.RenderPolicy(func(out io.Writer, contentType string, binding interface{}, options ...map[string]interface{}) (bool, error) {
+
+ if contentType == "text/html" {
+ if content, ok := binding.(string); ok {
+ out.Write([]byte("
My Custom prefix
" + content))
+ }
+
+ }
+ // continue to the next, no error
+ // note: if we wanted to stop here we would return true instead of false.
+ return false, nil
+ }))
+
+ app.Get("", func(ctx *iris.Context) {
+
+ // These content-types are not managed by our RenderPolicy:
+ // text, binary and html content-types are
+ // not rendered via serializers, you have to
+ // use the ctx.Render functions instead.
+ // so something like this:
+ // ctx.Text(iris.StatusOK, "my text content body here!")
+ // will NOT work with out custom render policy.
+ ctx.Render("text/html",
+ "my text content body here!")
+ })
+
+ app.Listen(":8080")
+}
diff --git a/adaptors/view/_examples/overview/main.go b/adaptors/view/_examples/overview/main.go
index c78e39e4..379e2202 100644
--- a/adaptors/view/_examples/overview/main.go
+++ b/adaptors/view/_examples/overview/main.go
@@ -55,39 +55,5 @@ func main() {
})
- // ------ first customization without even the need of *Context or a Handler--------
- //
- // Custom new content-/type:
- // app.Adapt(iris.RenderPolicy(func(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) (error, bool) {
- // if name == "customcontent-type" {
- //
- // // some very advanced things here:
- // out.Write([]byte(binding.(string)))
- // return nil, true
- // }
- // return nil, false
- // }))
- //
- // app.Get("/custom", func(ctx *iris.Context) {
- // ctx.RenderWithStatus(iris.StatusOK, // or MustRender
- // "customcontent-type",
- // "my custom content here!",
- // )
- // })
- //
- // ---- second -----------------------------------------------------------------------
- //
- // Override the defaults (the json,xml,jsonp,text,data and so on), an existing content-type:
- // app.Adapt(iris.RenderPolicy(func(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) (error, bool) {
- // if name == "text/plain" {
- // out.Write([]byte("From the custom text/plain renderer: " + binding.(string)))
- // return nil, true
- // }
- //
- // return nil, false
- // }))
- // // the context.Text's behaviors was changed now by your custom renderer.
- //
-
app.Listen(":8080")
}
diff --git a/fs.go b/fs.go
index 221053f9..2160fe22 100644
--- a/fs.go
+++ b/fs.go
@@ -20,13 +20,35 @@ import (
"github.com/kataras/go-errors"
)
+// StaticHandler returns a new Handler which is ready
+// to serve all kind of static files.
+//
+// Developers can wrap this handler using the `iris.StripPrefix`
+// for a fixed static path when the result handler is being, finally, registered to a route.
+//
+//
+// Usage:
+// app := iris.New()
+// ...
+// fileserver := iris.StaticHandler("./static_files", false, false)
+// h := iris.StripPrefix("/static", fileserver)
+// /* http://mydomain.com/static/css/style.css */
+// app.Get("/static", h)
+// ...
+//
+func StaticHandler(systemPath string, showList bool, enableGzip bool, exceptRoutes ...RouteInfo) HandlerFunc {
+ return NewStaticHandlerBuilder(systemPath).
+ Listing(showList).
+ Gzip(enableGzip).
+ Except(exceptRoutes...).
+ Build()
+}
+
// StaticHandlerBuilder is the web file system's Handler builder
// use that or the iris.StaticHandler/StaticWeb methods
type StaticHandlerBuilder interface {
- Path(requestRoutePath string) StaticHandlerBuilder
Gzip(enable bool) StaticHandlerBuilder
Listing(listDirectoriesOnOff bool) StaticHandlerBuilder
- StripPath(yesNo bool) StaticHandlerBuilder
Except(r ...RouteInfo) StaticHandlerBuilder
Build() HandlerFunc
}
@@ -40,8 +62,6 @@ type StaticHandlerBuilder interface {
type fsHandler struct {
// user options, only directory is required.
directory http.Dir
- requestPath string
- stripPath bool
gzip bool
listDirectories bool
// these are init on the Build() call
@@ -82,10 +102,6 @@ func abs(path string) string {
func NewStaticHandlerBuilder(dir string) StaticHandlerBuilder {
return &fsHandler{
directory: http.Dir(abs(dir)),
- // default route path is the same as the directory
- requestPath: toWebPath(dir),
- // enable strip path by-default
- stripPath: true,
// gzip is disabled by default
gzip: false,
// list directories disabled by default
@@ -93,13 +109,6 @@ func NewStaticHandlerBuilder(dir string) StaticHandlerBuilder {
}
}
-// Path sets the request path.
-// Defaults to same as system path
-func (w *fsHandler) Path(requestRoutePath string) StaticHandlerBuilder {
- w.requestPath = toWebPath(requestRoutePath)
- return w
-}
-
// Gzip if enable is true then gzip compression is enabled for this static directory
// Defaults to false
func (w *fsHandler) Gzip(enable bool) StaticHandlerBuilder {
@@ -114,11 +123,6 @@ func (w *fsHandler) Listing(listDirectoriesOnOff bool) StaticHandlerBuilder {
return w
}
-func (w *fsHandler) StripPath(yesNo bool) StaticHandlerBuilder {
- w.stripPath = yesNo
- return w
-}
-
// Except add a route exception,
// gives priority to that Route over the static handler.
func (w *fsHandler) Except(r ...RouteInfo) StaticHandlerBuilder {
@@ -160,7 +164,7 @@ func (w *fsHandler) Build() HandlerFunc {
w.once.Do(func() {
w.filesystem = w.directory
- hStatic := func(ctx *Context) {
+ fileserver := func(ctx *Context) {
upath := ctx.Request.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
@@ -203,14 +207,6 @@ func (w *fsHandler) Build() HandlerFunc {
}
}
- var fileserver HandlerFunc
-
- if w.stripPath {
- fileserver = StripPrefix(w.requestPath, hStatic)
- } else {
- fileserver = hStatic
- }
-
if len(w.exceptions) > 0 {
middleware := make(Middleware, len(w.exceptions)+1)
for i := range w.exceptions {
@@ -237,12 +233,26 @@ func (w *fsHandler) Build() HandlerFunc {
// 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.
+//
+// Usage:
+// fileserver := iris.StaticHandler("./static_files", false, false)
+// h := iris.StripPrefix("/static", fileserver)
+// app.Get("/static", h)
+//
func StripPrefix(prefix string, h HandlerFunc) HandlerFunc {
if prefix == "" {
return h
}
+ // 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
+ fixedPrefix := prefix
+ if dotWSlashIdx := strings.Index(fixedPrefix, subdomainIndicator); dotWSlashIdx > 0 {
+ fixedPrefix = fixedPrefix[dotWSlashIdx+1:]
+ }
+ fixedPrefix = toWebPath(fixedPrefix)
+
return func(ctx *Context) {
- if p := strings.TrimPrefix(ctx.Request.URL.Path, prefix); len(p) < len(ctx.Request.URL.Path) {
+ if p := strings.TrimPrefix(ctx.Request.URL.Path, fixedPrefix); len(p) < len(ctx.Request.URL.Path) {
ctx.Request.URL.Path = p
h(ctx)
} else {
diff --git a/router.go b/router.go
index 3f207f9b..313aafda 100644
--- a/router.go
+++ b/router.go
@@ -562,22 +562,27 @@ func (router *Router) Favicon(favPath string, requestPath ...string) RouteInfo {
return router.registerResourceRoute(reqPath, h)
}
-// StaticHandler returns a new Handler which serves static files
+// StaticHandler returns a new Handler which is ready
+// to serve all kind of static files.
+//
+// Note:
+// The only difference from package-level `StaticHandler`
+// is that this `StaticHandler`` receives a request path which
+// is appended to the party's relative path and stripped here,
+// so `iris.StripPath` is useless and should not being used here.
+//
+// Usage:
+// app := iris.New()
+// ...
+// mySubdomainFsServer := app.Party("mysubdomain.")
+// h := mySubdomainFsServer.StaticHandler("/static", "./static_files", false, false)
+// /* http://mysubdomain.mydomain.com/static/css/style.css */
+// mySubdomainFsServer.Get("/static", h)
+// ...
+//
func (router *Router) StaticHandler(reqPath string, systemPath string, showList bool, enableGzip bool, exceptRoutes ...RouteInfo) 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 := router.relativePath + reqPath
- path := fullpath
- if dotWSlashIdx := strings.Index(path, subdomainIndicator); dotWSlashIdx > 0 {
- path = fullpath[dotWSlashIdx+1:]
- }
-
- return NewStaticHandlerBuilder(systemPath).
- Path(path).
- Listing(showList).
- Gzip(enableGzip).
- Except(exceptRoutes...).
- Build()
+ return StripPrefix(router.relativePath+reqPath,
+ StaticHandler(systemPath, showList, enableGzip))
}
// StaticWeb returns a handler that serves HTTP requests
@@ -602,15 +607,17 @@ func (router *Router) StaticWeb(reqPath string, systemPath string, exceptRoutes
routePath := router.Context.Framework().RouteWildcardPath(reqPath, paramName)
handler := func(ctx *Context) {
h(ctx)
- if fname := ctx.Param(paramName); fname != "" {
- cType := typeByExtension(fname)
- if cType != contentBinary && !strings.Contains(cType, "charset") {
- cType += "; charset=" + ctx.framework.Config.Charset
+ // re-check the content type here for any case,
+ // although the new code does it automatically but it's good to have it here.
+ if ctx.StatusCode() >= 200 && ctx.StatusCode() < 400 {
+ if fname := ctx.Param(paramName); fname != "" {
+ cType := typeByExtension(fname)
+ if cType != contentBinary && !strings.Contains(cType, "charset") {
+ cType += "; charset=" + ctx.framework.Config.Charset
+ }
+ ctx.SetContentType(cType)
}
-
- ctx.SetContentType(cType)
}
-
}
return router.registerResourceRoute(routePath, handler)