//go:build !go1.16 // +build !go1.16 package echo import ( "net/http" "net/url" "os" "path/filepath" ) type filesystem struct { } func createFilesystem() filesystem { return filesystem{} } // Static registers a new route with path prefix to serve static files from the // provided root directory. func (e *Echo) Static(prefix, root string) *Route { if root == "" { root = "." // For security we want to restrict to CWD. } return e.static(prefix, root, e.GET) } func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route { h := func(c Context) error { p, err := url.PathUnescape(c.Param("*")) if err != nil { return err } name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security fi, err := os.Stat(name) if err != nil { // The access path does not exist return NotFoundHandler(c) } // If the request is for a directory and does not end with "/" p = c.Request().URL.Path // path must not be empty. if fi.IsDir() && p[len(p)-1] != '/' { // Redirect to ends with "/" return c.Redirect(http.StatusMovedPermanently, p+"/") } return c.File(name) } // Handle added routes based on trailing slash: // /prefix => exact route "/prefix" + any route "/prefix/*" // /prefix/ => only any route "/prefix/*" if prefix != "" { if prefix[len(prefix)-1] == '/' { // Only add any route for intentional trailing slash return get(prefix+"*", h) } get(prefix, h) } return get(prefix+"/*", h) }