diff options
Diffstat (limited to 'vendor/github.com/labstack/echo/v4/middleware/static.go')
-rw-r--r-- | vendor/github.com/labstack/echo/v4/middleware/static.go | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/vendor/github.com/labstack/echo/v4/middleware/static.go b/vendor/github.com/labstack/echo/v4/middleware/static.go new file mode 100644 index 00000000..bc2087a7 --- /dev/null +++ b/vendor/github.com/labstack/echo/v4/middleware/static.go @@ -0,0 +1,229 @@ +package middleware + +import ( + "fmt" + "html/template" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "strings" + + "github.com/labstack/echo/v4" + "github.com/labstack/gommon/bytes" +) + +type ( + // StaticConfig defines the config for Static middleware. + StaticConfig struct { + // Skipper defines a function to skip middleware. + Skipper Skipper + + // Root directory from where the static content is served. + // Required. + Root string `yaml:"root"` + + // Index file for serving a directory. + // Optional. Default value "index.html". + Index string `yaml:"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 `yaml:"html5"` + + // Enable directory browsing. + // Optional. Default value false. + Browse bool `yaml:"browse"` + } +) + +const html = ` +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <title>{{ .Name }}</title> + <style> + body { + font-family: Menlo, Consolas, monospace; + padding: 48px; + } + header { + padding: 4px 16px; + font-size: 24px; + } + ul { + list-style-type: none; + margin: 0; + padding: 20px 0 0 0; + display: flex; + flex-wrap: wrap; + } + li { + width: 300px; + padding: 16px; + } + li a { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + text-decoration: none; + transition: opacity 0.25s; + } + li span { + color: #707070; + font-size: 12px; + } + li a:hover { + opacity: 0.50; + } + .dir { + color: #E91E63; + } + .file { + color: #673AB7; + } + </style> +</head> +<body> + <header> + {{ .Name }} + </header> + <ul> + {{ range .Files }} + <li> + {{ if .Dir }} + {{ $name := print .Name "/" }} + <a class="dir" href="{{ $name }}">{{ $name }}</a> + {{ else }} + <a class="file" href="{{ .Name }}">{{ .Name }}</a> + <span>{{ .Size }}</span> + {{ end }} + </li> + {{ end }} + </ul> +</body> +</html> +` + +var ( + // DefaultStaticConfig is the default Static middleware config. + DefaultStaticConfig = StaticConfig{ + Skipper: DefaultSkipper, + 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 with config. +// See `Static()`. +func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc { + // Defaults + if config.Root == "" { + config.Root = "." // For security we want to restrict to CWD. + } + if config.Skipper == nil { + config.Skipper = DefaultStaticConfig.Skipper + } + if config.Index == "" { + config.Index = DefaultStaticConfig.Index + } + + // Index template + t, err := template.New("index").Parse(html) + if err != nil { + panic(fmt.Sprintf("echo: %v", err)) + } + + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) (err error) { + if config.Skipper(c) { + return next(c) + } + + p := c.Request().URL.Path + if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`. + p = c.Param("*") + } + p, err = url.PathUnescape(p) + if err != nil { + return + } + name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security + + fi, err := os.Stat(name) + if err != nil { + if os.IsNotExist(err) { + if err = next(c); err != nil { + if he, ok := err.(*echo.HTTPError); ok { + if config.HTML5 && he.Code == http.StatusNotFound { + return c.File(filepath.Join(config.Root, config.Index)) + } + } + return + } + } + return + } + + if fi.IsDir() { + index := filepath.Join(name, config.Index) + fi, err = os.Stat(index) + + if err != nil { + if config.Browse { + return listDir(t, name, c.Response()) + } + if os.IsNotExist(err) { + return next(c) + } + return + } + + return c.File(index) + } + + return c.File(name) + } + } +} + +func listDir(t *template.Template, name string, res *echo.Response) (err error) { + file, err := os.Open(name) + if err != nil { + return + } + files, err := file.Readdir(-1) + if err != nil { + return + } + + // Create directory index + res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8) + data := struct { + Name string + Files []interface{} + }{ + Name: name, + } + for _, f := range files { + data.Files = append(data.Files, struct { + Name string + Dir bool + Size string + }{f.Name(), f.IsDir(), bytes.Format(f.Size())}) + } + return t.Execute(res, data) +} |