forked from labstack/echo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
static.go
133 lines (120 loc) · 3.08 KB
/
static.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package middleware
import (
"fmt"
"net/http"
"path"
"strings"
"github.com/labstack/echo"
)
type (
// StaticConfig defines the config for static middleware.
StaticConfig struct {
// Root directory from where the static content is served.
// Required.
Root string `json:"root"`
// Index file for serving a directory.
// Optional. Default value "index.html".
Index string `json:"index"`
// Enable HTML5 mode by forwarding all not-found requests to root so that
// SPA (single-page application) can handle the routing.
// Optional. Default value false.
HTML5 bool `json:"html5"`
// Enable directory browsing.
// Optional. Default value false.
Browse bool `json:"browse"`
}
)
var (
// DefaultStaticConfig is the default static middleware config.
DefaultStaticConfig = StaticConfig{
Index: "index.html",
}
)
// Static returns a static middleware to serves static content from the provided
// root directory.
func Static(root string) echo.MiddlewareFunc {
c := DefaultStaticConfig
c.Root = root
return StaticWithConfig(c)
}
// StaticWithConfig returns a static middleware from config.
// See `Static()`.
func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
// Defaults
if config.Index == "" {
config.Index = DefaultStaticConfig.Index
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
fs := http.Dir(config.Root)
p := c.Request().URL().Path()
if strings.Contains(c.Path(), "*") { // If serving from a group, e.g. `/static*`.
p = c.P(0)
}
file := path.Clean(p)
f, err := fs.Open(file)
if err != nil {
// HTML5 mode
err = next(c)
if he, ok := err.(*echo.HTTPError); ok {
if config.HTML5 && he.Code == http.StatusNotFound {
file = ""
f, err = fs.Open(file)
} else {
return err
}
} else {
return err
}
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
if fi.IsDir() {
/* NOTE:
Not checking the Last-Modified header as it caches the response `304` when
changing different directories for the same path.
*/
d := f
// Index file
file = path.Join(file, config.Index)
f, err = fs.Open(file)
if err == nil {
// Index file
if fi, err = f.Stat(); err != nil {
return err
}
} else if err != nil && config.Browse {
dirs, err := d.Readdir(-1)
if err != nil {
return err
}
// Create a directory index
res := c.Response()
res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
return err
}
for _, d := range dirs {
name := d.Name()
color := "#212121"
if d.IsDir() {
color = "#e91e63"
name += "/"
}
if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
return err
}
}
_, err = fmt.Fprintf(res, "</pre>\n")
return err
} else {
return next(c)
}
}
return c.ServeContent(f, fi.Name(), fi.ModTime())
}
}
}