aboutsummaryrefslogtreecommitdiff
path: root/echo/static_file.go
diff options
context:
space:
mode:
Diffstat (limited to 'echo/static_file.go')
-rw-r--r--echo/static_file.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/echo/static_file.go b/echo/static_file.go
new file mode 100644
index 0000000..9723db7
--- /dev/null
+++ b/echo/static_file.go
@@ -0,0 +1,71 @@
1package echo
2
3import (
4 "io"
5 "io/fs"
6 "net/http"
7 "net/url"
8 "path/filepath"
9
10 "github.com/labstack/echo/v4"
11)
12
13type routeFunc func(string, echo.HandlerFunc, ...echo.MiddlewareFunc) *echo.Route
14
15func StaticFS(get routeFunc, f fs.FS, prefix, root string, m ...echo.MiddlewareFunc) *echo.Route {
16 if root == "" {
17 root = "." // For security we want to restrict to CWD.
18 }
19
20 h := func(c echo.Context) error {
21 p, err := url.PathUnescape(c.Param("*"))
22 if err != nil {
23 return err
24 }
25
26 name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
27 fp, err := f.Open(name)
28 if err != nil {
29 // The access path does not exist
30 return echo.NotFoundHandler(c)
31 }
32 defer fp.Close()
33
34 fi, err := fp.Stat()
35 if err != nil {
36 // The access path does not exist
37 return echo.NotFoundHandler(c)
38 }
39
40 // If the request is for a directory and does not end with "/"
41 p = c.Request().URL.Path // path must not be empty.
42 if fi.IsDir() && p[len(p)-1] != '/' {
43 // Redirect to ends with "/"
44 // return c.Redirect(http.StatusMovedPermanently, p+"/")
45 // TODO: Serve an index.html if there is one for this dir
46 return echo.NotFoundHandler(c)
47 }
48
49 fs, ok := fp.(io.ReadSeeker)
50 if !ok {
51 c.Logger().Errorf("File %s is not a io.ReadSeeker", p)
52 return echo.ErrInternalServerError
53 }
54
55 http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), fs)
56 return nil
57 }
58
59 // Handle added routes based on trailing slash:
60 // /prefix => exact route "/prefix" + any route "/prefix/*"
61 // /prefix/ => only any route "/prefix/*"
62 if prefix != "" {
63 if prefix[len(prefix)-1] == '/' {
64 // Only add any route for intentional trailing slash
65 return get(prefix+"*", h, m...)
66 }
67 get(prefix, h, m...)
68 }
69
70 return get(prefix+"/*", h, m...)
71}