Skip to content

Commit da5f798

Browse files
committed
Fix e.File(), c.Attachment(), being picky with relative paths after 4.7.0 introduced echo.Fs support
1 parent 37e77f2 commit da5f798

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

echo_fs_go1.16.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
9494
}
9595
}
9696

97-
// defaultFS emulates os.Open behaviour with filesystem opened by `os.DirFs`. Difference between `os.Open` and `fs.Open`
98-
// is that FS does not allow to open path that start with `..` or `/` etc. For example previously you could have `../images`
99-
// in your application but `fs := os.DirFS("./")` would not allow you to use `fs.Open("../images")` and this would break
100-
// all old applications that rely on being able to traverse up from current executable run path.
97+
// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
98+
// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
99+
// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
100+
// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
101+
// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
102+
// traverse up from current executable run path.
101103
// NB: private because you really should use fs.FS implementation instances
102104
type defaultFS struct {
103105
prefix string
@@ -108,20 +110,26 @@ func newDefaultFS() *defaultFS {
108110
dir, _ := os.Getwd()
109111
return &defaultFS{
110112
prefix: dir,
111-
fs: os.DirFS(dir),
113+
fs: nil,
112114
}
113115
}
114116

115117
func (fs defaultFS) Open(name string) (fs.File, error) {
116-
return fs.fs.Open(filepath.ToSlash(filepath.Clean(name)))
118+
if fs.fs == nil {
119+
return os.Open(name)
120+
}
121+
return fs.fs.Open(name)
117122
}
118123

119124
func subFS(currentFs fs.FS, root string) (fs.FS, error) {
120125
root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
121126
if dFS, ok := currentFs.(*defaultFS); ok {
122-
// we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS to
123-
// allow cases when root is given as `../somepath` which is not valid for fs.FS
124-
root = filepath.Join(dFS.prefix, root)
127+
// we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
128+
// fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
129+
// were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
130+
if len(root) > 0 && root[0] != '/' {
131+
root = filepath.Join(dFS.prefix, root)
132+
}
125133
return &defaultFS{
126134
prefix: root,
127135
fs: os.DirFS(root),

0 commit comments

Comments
 (0)