diff --git a/HISTORY.md b/HISTORY.md index c157797f..bbeeb44a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,77 @@ **How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`. +## 4.6.0 -> 4.6.1 + +- **NEW**: `iris.StaticEmbedded`/`app := iris.New(); app.StaticEmbedded` - Embed static assets into your executable with [go-bindata](https://github.com/jteeuwen/go-bindata) and serve them. + +> Note: This was already buitl'n feature for templates using `iris.UseTemplate(html.New()).Directory("./templates",".html").Binary(Asset,AssetNames)`, after v4.6.1 you can do that for other static files too, with the `StaticEmbedded` function + +**outline** +```go + +// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly +// First parameter is the request path, the path which the files in the vdir(second parameter) will be served to, for example "/static" +// Second parameter is the (virtual) directory path, for example "./assets" +// Third parameter is the Asset function +// Forth parameter is the AssetNames function +// +// For more take a look at the +// example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded +StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) RouteNameFunc + +``` + +**example** + +You can view and run it from [here](https://github.com/iris-contrib/examples/tree/master/static_files_embedded) * + +```go +package main + +// First of all, execute: $ go get https://github.com/jteeuwen/go-bindata +// Secondly, execute the command: cd $GOPATH/src/github.com/iris-contrib/examples/static_files_embedded && go-bindata ./assets/... + +import ( + "github.com/kataras/iris" +) + +func main() { + + // executing this go-bindata command creates a source file named 'bindata.go' which + // gives you the Asset and AssetNames funcs which we will pass into .StaticAssets + // for more viist: https://github.com/jteeuwen/go-bindata + // Iris gives you a way to integrade these functions to your web app + + // For the reason that you may use go-bindata to embed more than your assets, you should pass the 'virtual directory path', for example here is the : "./assets" + // and the request path, which these files will be served to, you can set as "/assets" or "/static" which resulting on http://localhost:8080/static/*anyfile.*extension + iris.StaticEmbedded("/static", "./assets", Asset, AssetNames) + + + // that's all + // this will serve the ./assets (embedded) files to the /static request path for example the favicon.ico will be served as : + // http://localhost:8080/static/favicon.ico + // Methods: GET and HEAD + + + + iris.Get("/", func(ctx *iris.Context) { + ctx.HTML(iris.StatusOK, " Hi from index") + }) + + iris.Listen(":8080") +} + +// Navigate to: +// http://localhost:8080/static/favicon.ico +// http://localhost:8080/static/js/jquery-2.1.1.js +// http://localhost:8080/static/css/bootstrap.min.css + +// Now, these files are stored inside into your executable program, no need to keep it in the same location with your assets folder. + + +``` + ## 4.5.2/.3 -> 4.6.0 diff --git a/README.md b/README.md index dcebfc61..1f6cdeb9 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@
-Releases +Releases Examples @@ -869,7 +869,7 @@ I recommend writing your API tests using this new library, [httpexpect](https:// Versioning ------------ -Current: **v4.6.0** +Current: **v4.6.1** > Iris is an active project @@ -905,7 +905,7 @@ This project is licensed under the [Apache License, Version 2.0](LICENSE), Copyr [Travis]: http://travis-ci.org/kataras/iris [License Widget]: https://img.shields.io/badge/license-Apache%20Version%202-E91E63.svg?style=flat-square [License]: https://github.com/kataras/iris/blob/master/LICENSE -[Release Widget]: https://img.shields.io/badge/release-4.6.0%20-blue.svg?style=flat-square +[Release Widget]: https://img.shields.io/badge/release-4.6.1%20-blue.svg?style=flat-square [Release]: https://github.com/kataras/iris/releases [Chat Widget]: https://img.shields.io/badge/community-chat%20-00BCD4.svg?style=flat-square [Chat]: https://kataras.rocket.chat/channel/iris diff --git a/iris.go b/iris.go index fd1b7585..045824a8 100644 --- a/iris.go +++ b/iris.go @@ -76,7 +76,7 @@ import ( const ( // Version is the current version of the Iris web framework - Version = "4.6.0" + Version = "4.6.1" banner = ` _____ _ |_ _| (_) @@ -1157,6 +1157,7 @@ type ( StaticWeb(string, string, int) RouteNameFunc StaticServe(string, ...string) RouteNameFunc StaticContent(string, string, []byte) RouteNameFunc + StaticEmbedded(string, string, func(string) ([]byte, error), func() []string) RouteNameFunc Favicon(string, ...string) RouteNameFunc // templates @@ -1702,8 +1703,8 @@ func (api *muxAPI) StaticHandler(systemPath string, stripSlashes int, compress b // * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar" // * stripSlashes = 1, original path: "/foo/bar", result: "/bar" // * stripSlashes = 2, original path: "/foo/bar", result: "" -func Static(relative string, systemPath string, stripSlashes int) RouteNameFunc { - return Default.Static(relative, systemPath, stripSlashes) +func Static(reqPath string, systemPath string, stripSlashes int) RouteNameFunc { + return Default.Static(reqPath, systemPath, stripSlashes) } // Static registers a route which serves a system directory @@ -1716,15 +1717,15 @@ func Static(relative string, systemPath string, stripSlashes int) RouteNameFunc // * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar" // * stripSlashes = 1, original path: "/foo/bar", result: "/bar" // * stripSlashes = 2, original path: "/foo/bar", result: "" -func (api *muxAPI) Static(relative string, systemPath string, stripSlashes int) RouteNameFunc { - if relative[len(relative)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath - relative += slash +func (api *muxAPI) Static(reqPath string, systemPath string, stripSlashes int) RouteNameFunc { + if reqPath[len(reqPath)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath + reqPath += slash } h := api.StaticHandler(systemPath, stripSlashes, false, false, nil) - api.Head(relative+"*filepath", h) - return api.Get(relative+"*filepath", h) + api.Head(reqPath+"*filepath", h) + return api.Get(reqPath+"*filepath", h) } // StaticFS registers a route which serves a system directory @@ -1877,6 +1878,128 @@ func (api *muxAPI) StaticContent(reqPath string, cType string, content []byte) R return api.Get(reqPath, h) } +// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly +// First parameter is the request path, the path which the files in the vdir(second parameter) will be served to, for example "/static" +// Second parameter is the (virtual) directory path, for example "./assets" +// Third parameter is the Asset function +// Forth parameter is the AssetNames function +// +// For more take a look at the +// example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded +func StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) RouteNameFunc { + return Default.StaticEmbedded(requestPath, vdir, assetFn, namesFn) +} + +// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly +// First parameter is the request path, the path which the files in the vdir will be served to, for example "/static" +// Second parameter is the (virtual) directory path, for example "./assets" +// Third parameter is the Asset function +// Forth parameter is the AssetNames function +// +// For more take a look at the +// example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded +func (api *muxAPI) StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) RouteNameFunc { + + // check if requestPath already contains an asterix-match to anything symbol: /path/* + requestPath = strings.Replace(requestPath, "//", "/", -1) + matchEverythingIdx := strings.IndexByte(requestPath, matchEverythingByte) + paramName := "path" + + if matchEverythingIdx != -1 { + // found so it should has a param name, take it + paramName = requestPath[matchEverythingIdx+1:] + } else { + // make the requestPath + if requestPath[len(requestPath)-1] == slashByte { + // ends with / remove it + requestPath = requestPath[0 : len(requestPath)-2] + } + + requestPath += slash + "*" + paramName // $requestPath/*path + } + + if len(vdir) > 0 { + if vdir[0] == '.' { // first check for .wrong + vdir = vdir[1:] + } + if vdir[0] == '/' || vdir[0] == os.PathSeparator { // second check for /something, (or ./something if we had dot on 0 it will be removed + vdir = vdir[1:] + } + } + + // collect the names we are care for, because not all Asset used here, we need the vdir's assets. + allNames := namesFn() + + var names []string + for _, path := range allNames { + // check if path is the path name we care for + if !strings.HasPrefix(path, vdir) { + continue + } + + path = strings.Replace(path, "\\", "/", -1) // replace system paths with double slashes + path = strings.Replace(path, "./", "/", -1) // replace ./assets/favicon.ico to /assets/favicon.ico in order to be ready for compare with the reqPath later + path = path[len(vdir):] // set it as the its 'relative' ( we should re-setted it when assetFn will be used) + names = append(names, path) + + } + if len(names) == 0 { + // we don't start the server yet, so: + panic("iris.StaticEmbedded: Unable to locate any embedded files located to the (virutal) directory: " + vdir) + } + + modtime := time.Now() + modtimeStr := "" + h := func(ctx *Context) { + + reqPath := ctx.Param(paramName) + + for _, path := range names { + + if path != reqPath { + continue + } + + cType := fs.TypeByExtension(path) + fullpath := vdir + path + + buf, err := assetFn(fullpath) + + if err != nil { + continue + } + + if modtimeStr == "" { + modtimeStr = modtime.UTC().Format(ctx.framework.Config.TimeFormat) + } + + if t, err := time.Parse(ctx.framework.Config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && modtime.Before(t.Add(StaticCacheDuration)) { + ctx.Response.Header.Del(contentType) + ctx.Response.Header.Del(contentLength) + ctx.SetStatusCode(StatusNotModified) + return + } + + ctx.Response.Header.Set(contentType, cType) + ctx.Response.Header.Set(lastModified, modtimeStr) + + ctx.SetStatusCode(StatusOK) + ctx.SetContentType(cType) + + ctx.Response.SetBody(buf) + return + } + + // not found + ctx.EmitError(StatusNotFound) + + } + + api.Head(requestPath, h) + + return api.Get(requestPath, h) +} + // Favicon serves static favicon // accepts 2 parameters, second is optional // favPath (string), declare the system directory path of the __.ico