package echo import ( "errors" "io" "io/fs" "net/http" "path/filepath" ) func (c *context) File(file string) error { return fsFile(c, file, c.echo.Filesystem) } // FileFS serves file from given file system. // // When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary // prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths // including `assets/images` as their prefix. func (c *context) FileFS(file string, filesystem fs.FS) error { return fsFile(c, file, filesystem) } func fsFile(c Context, file string, filesystem fs.FS) error { f, err := filesystem.Open(file) if err != nil { return ErrNotFound } defer f.Close() fi, _ := f.Stat() if fi.IsDir() { file = filepath.ToSlash(filepath.Join(file, indexPage)) // ToSlash is necessary for Windows. fs.Open and os.Open are different in that aspect. f, err = filesystem.Open(file) if err != nil { return ErrNotFound } defer f.Close() if fi, err = f.Stat(); err != nil { return err } } ff, ok := f.(io.ReadSeeker) if !ok { return errors.New("file does not implement io.ReadSeeker") } http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), ff) return nil }