Skip to content

Commit

Permalink
New iris.DirOptions.PushTargetsRegexp
Browse files Browse the repository at this point in the history
  • Loading branch information
kataras committed Jul 18, 2020
1 parent ea85095 commit 8cf3dac
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 12 deletions.
17 changes: 15 additions & 2 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,20 @@ Other Improvements:

![DBUG routes](https://iris-go.com/images/v12.2.0-dbug2.png?v=0)

- Fix [#1562](https://github.com/kataras/iris/issues/1562)
- New `DirOptions.PushTargets` and `PushTargetsRegexp` to push index' assets to the client without additional requests. Inspirated by issue [#1562](https://github.com/kataras/iris/issues/1562). Example matching all `.js, .css and .ico` files (recursively):

```go
var opts = iris.DirOptions{
IndexName: "/index.html",
PushTargetsRegexp: map[string]*regexp.Regexp{
"/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$"),
// OR:
// "/": iris.MatchCommonAssets,
},
Compress: true,
}
```

- Update jet parser to v4.0.2, closes [#1551](https://github.com/kataras/iris/issues/1551). It contains two breaking changes by its author:
- Relative paths on `extends, import, include...` tmpl functions, e.g. `{{extends "../layouts/application.jet"}}` instead of `layouts/application.jet`
- the new [jet.Ranger](https://github.com/CloudyKit/jet/pull/165) interface now requires a `ProvidesIndex() bool` method too
Expand All @@ -380,7 +393,7 @@ Other Improvements:
- Fix [#1552](https://github.com/kataras/iris/issues/1552).

- Proper listing of root directories on `Party.HandleDir` when its `DirOptions.ShowList` was set to true.
- Customize the file/directory listing page through views, see [example](https://github.com/kataras/iris/tree/master/_examples/file-server/file-server)
- Customize the file/directory listing page through views, see [example](https://github.com/kataras/iris/tree/master/_examples/file-server/file-server).

- Socket Sharding as requested at [#1544](https://github.com/kataras/iris/issues/1544). New `iris.WithSocketSharding` Configurator and `SocketSharding bool` setting.

Expand Down
23 changes: 16 additions & 7 deletions _examples/file-server/http2push/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package main

import (
"regexp"

"github.com/kataras/iris/v12"
)

Expand All @@ -13,13 +15,20 @@ var opts = iris.DirOptions{
//
// Note: Requires running server under TLS,
// that's why we use `iris.TLS` below.
PushTargets: map[string][]string{
"/": { // Relative path without route prefix.
"favicon.ico",
"js/main.js",
"css/main.css",
// ^ Relative to the index, if need absolute ones start with a slash ('/').
},
// PushTargets: map[string][]string{
// "/": { // Relative path without prefix.
// "favicon.ico",
// "js/main.js",
// "css/main.css",
// // ^ Relative to the index, if need absolute ones start with a slash ('/').
// },
// },
// OR use regexp:
PushTargetsRegexp: map[string]*regexp.Regexp{
// Match all js, css and ico files
// from all files (recursively).
// "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$"),
"/": iris.MatchCommonAssets,
},
Compress: true,
ShowList: true,
Expand Down
8 changes: 8 additions & 0 deletions aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package iris

import (
"net/http"
"regexp"

"github.com/kataras/iris/v12/cache"
"github.com/kataras/iris/v12/context"
Expand Down Expand Up @@ -216,6 +217,13 @@ var (
ctx.CompressReader(true)
ctx.Next()
}

// MatchCommonAssets is a simple regex expression which
// can be used on `DirOptions.PushTargetsRegexp`.
// It will match and Push
// all available js, css, font and media files.
// Ideal for Single Page Applications.
MatchCommonAssets = regexp.MustCompile("((.*).js|(.*).css|(.*).ico|(.*).png|(.*).ttf|(.*).svg|(.*).webp|(.*).gif)$")
)

var (
Expand Down
80 changes: 77 additions & 3 deletions core/router/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -48,7 +49,23 @@ type DirOptions struct {
// be served without additional client's requests (HTTP/2 Push)
// when a specific request path (map's key WITHOUT prefix)
// is requested and it's not a directory (it's an `IndexFile`).
//
// Example:
// "/": {
// "favicon.ico",
// "js/main.js",
// "css/main.css",
// }
PushTargets map[string][]string
// PushTargetsRegexp like `PushTargets` but accepts regexp which
// is compared against all files under a directory (recursively).
// The `IndexName` should be set.
//
// Example:
// "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$")
// See `iris.MatchCommonAssets` too.
PushTargetsRegexp map[string]*regexp.Regexp

// When files should served under compression.
Compress bool

Expand Down Expand Up @@ -407,7 +424,11 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
return
}

indexFound := false
var (
indexFound bool
indexDirectory http.File
)

// use contents of index.html for directory, if present
if info.IsDir() && options.IndexName != "" {
// Note that, in contrast of the default net/http mechanism;
Expand All @@ -425,9 +446,11 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
defer fIndex.Close()
infoIndex, err := fIndex.Stat()
if err == nil {
info = infoIndex
f = fIndex
indexFound = true
indexDirectory = f

f = fIndex
info = infoIndex
}
}
}
Expand All @@ -454,6 +477,25 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
}
}
}

if regex, ok := options.PushTargetsRegexp[r.URL.Path]; ok {
if pusher, ok := ctx.ResponseWriter().(http.Pusher); ok {
for _, indexAsset := range getFilenamesRecursively(fs, indexDirectory, "") {
// it's an index file, do not pushed that.
if strings.HasSuffix("/"+indexAsset, options.IndexName) {
continue
}
// match using relative path (without the first '/' slash)
// to keep consistency between the `PushTargets` behavior
if regex.MatchString(indexAsset) {
// println("Regex Matched: " + indexAsset)
if err = pusher.Push(path.Join(r.RequestURI, indexAsset), nil); err != nil {
break
}
}
}
}
}
}

// Still a directory? (we didn't find an index.html file)
Expand Down Expand Up @@ -532,6 +574,38 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
return h
}

func getFilenamesRecursively(fs http.FileSystem, f http.File, parent string) []string {
defer f.Close()
info, err := f.Stat()
if err != nil {
return nil
}

var filenames []string

if info.IsDir() {
fileinfos, err := f.Readdir(-1)
if err != nil {
return nil
}

for _, fileinfo := range fileinfos {
fullname := path.Join(parent, fileinfo.Name())
ff, err := fs.Open(fullname)
if err != nil {
return nil
}

filenames = append(filenames, getFilenamesRecursively(fs, ff, fullname)...)
}

return filenames
}

filenames = append(filenames, path.Dir(path.Join(parent, info.Name())))
return filenames
}

// 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
Expand Down

0 comments on commit 8cf3dac

Please sign in to comment.