feat: recursive fallback resolution

This commit is contained in:
Nigel Sim 2019-10-15 23:02:26 +10:00
parent 3f97f57aae
commit 90ee9f39bc
3 changed files with 34 additions and 9 deletions

View file

@ -49,7 +49,7 @@ Usage of /goStatic:
-enable-basic-auth -enable-basic-auth
Enable basic auth. By default, password are randomly generated. Use --set-basic-auth to set it. Enable basic auth. By default, password are randomly generated. Use --set-basic-auth to set it.
-fallback string -fallback string
Default relative to be used when no file requested found. E.g. /index.html Default fallback file. Either absolute for a specific asset (/index.html), or relative to recursively resolve (index.html).
-password-length int -password-length int
Size of the randomized password (default 16) Size of the randomized password (default 16)
-path string -path string
@ -59,3 +59,12 @@ Usage of /goStatic:
-set-basic-auth string -set-basic-auth string
Define the basic auth. Form must be user:password Define the basic auth. Form must be user:password
``` ```
#### Fallback
The fallback option is principally useful for single page applications (SPAs) where the browser may request a file, but where part of the path is in fact an internal route in the application, not a file on disk. goStatic supports two possible usages of this option:
1. Using an absolute path so that all not found requests resolve to the same file
2. Using a relative file, which searches up the tree for the specified file
The second case is useful if you have multiple SPAs within the one filesystem. e.g., */* and */admin*.

View file

@ -3,6 +3,7 @@ package main
import ( import (
"net/http" "net/http"
"os" "os"
"path"
) )
// fallback opens defaultPath when the underlying fs returns os.ErrNotExist // fallback opens defaultPath when the underlying fs returns os.ErrNotExist
@ -11,10 +12,25 @@ type fallback struct {
fs http.FileSystem fs http.FileSystem
} }
func (fb fallback) Open(path string) (http.File, error) { func OpenDefault(fb fallback, requestPath string) (http.File, error) {
f, err := fb.fs.Open(path) requestPath = path.Dir(requestPath)
if os.IsNotExist(err) { defaultFile := requestPath + "/" + fb.defaultPath;
return fb.fs.Open(fb.defaultPath)
f, err := fb.fs.Open(defaultFile)
if os.IsNotExist(err) && requestPath != "" {
parentPath, _ := path.Split(requestPath)
return OpenDefault(fb, parentPath)
}
return f, err
}
func (fb fallback) Open(requestPath string) (http.File, error) {
f, err := fb.fs.Open(requestPath)
if os.IsNotExist(err) {
if len(fb.defaultPath) == 0 || fb.defaultPath[0] == '/' {
return fb.fs.Open(fb.defaultPath)
}
return OpenDefault(fb, requestPath)
} }
return f, err return f, err
} }

View file

@ -15,8 +15,8 @@ var (
// Def of flags // Def of flags
portPtr = flag.Int("port", 8043, "The listening port") portPtr = flag.Int("port", 8043, "The listening port")
context = flag.String("context", "", "The 'context' path on which files are served, e.g. 'doc' will serve the files at 'http://localhost:<port>/doc/'") context = flag.String("context", "", "The 'context' path on which files are served, e.g. 'doc' will serve the files at 'http://localhost:<port>/doc/'")
path = flag.String("path", "/srv/http", "The path for the static files") basePath = flag.String("path", "/srv/http", "The path for the static files")
fallbackPath = flag.String("fallback", "", "Default relative to be used when no file requested found. E.g. /index.html") fallbackPath = flag.String("fallback", "", "Default fallback file. Either absolute for a specific asset (/index.html), or relative to recursively resolve (index.html)")
headerFlag = flag.String("append-header", "", "HTTP response header, specified as `HeaderName:Value` that should be added to all responses.") headerFlag = flag.String("append-header", "", "HTTP response header, specified as `HeaderName:Value` that should be added to all responses.")
basicAuth = flag.Bool("enable-basic-auth", false, "Enable basic auth. By default, password are randomly generated. Use --set-basic-auth to set it.") basicAuth = flag.Bool("enable-basic-auth", false, "Enable basic auth. By default, password are randomly generated. Use --set-basic-auth to set it.")
setBasicAuth = flag.String("set-basic-auth", "", "Define the basic auth. Form must be user:password") setBasicAuth = flag.String("set-basic-auth", "", "Define the basic auth. Form must be user:password")
@ -49,7 +49,7 @@ func main() {
port := ":" + strconv.FormatInt(int64(*portPtr), 10) port := ":" + strconv.FormatInt(int64(*portPtr), 10)
var fileSystem http.FileSystem = http.Dir(*path) var fileSystem http.FileSystem = http.Dir(*basePath)
if *fallbackPath != "" { if *fallbackPath != "" {
fileSystem = fallback{ fileSystem = fallback{