func servefile(c *ctx, f http.File) error { fi, err := f.Stat() if err == nil { http.ServeContent(c.RW, c.Request, fi.Name(), fi.ModTime(), f) } return err }
func serveContent(w http.ResponseWriter, r *http.Request, f http.File, fname string) { var modtime time.Time if fi, err := f.Stat(); err != nil { modtime = fi.ModTime() } http.ServeContent(w, r, fname, modtime, f) }
// NewFromHTTPFile returns new *StaticFile from f func NewFromHTTPFile(f http.File) (*StaticFile, error) { info, err := f.Stat() if err != nil { return nil, err } b, _ := ioutil.ReadAll(f) return &StaticFile{rsc: bytes.NewReader(b), info: info}, nil }
// Server returns a handler that serves the files as the response content. // The files being served are determined using the current URL path and the specified path map. // For example, if the path map is {"/css": "/www/css", "/js": "/www/js"} and the current URL path // "/css/main.css", the file "<working dir>/www/css/main.css" will be served. // If a URL path matches multiple prefixes in the path map, the most specific prefix will take precedence. // For example, if the path map contains both "/css" and "/css/img", and the URL path is "/css/img/logo.gif", // then the path mapped by "/css/img" will be used. // // import ( // "log" // "github.com/go-ozzo/ozzo-routing" // "github.com/go-ozzo/ozzo-routing/file" // ) // // r := routing.New() // r.Get("/*", file.Server(file.PathMap{ // "/css": "/ui/dist/css", // "/js": "/ui/dist/js", // })) func Server(pathMap PathMap, opts ...ServerOptions) routing.Handler { var options ServerOptions if len(opts) > 0 { options = opts[0] } if !filepath.IsAbs(options.RootPath) { options.RootPath = filepath.Join(RootPath, options.RootPath) } from, to := parsePathMap(pathMap) // security measure: limit the files within options.RootPath dir := http.Dir(options.RootPath) return func(c *routing.Context) error { if c.Request.Method != "GET" && c.Request.Method != "HEAD" { return routing.NewHTTPError(http.StatusMethodNotAllowed) } path, found := matchPath(c.Request.URL.Path, from, to) if !found || options.Allow != nil && !options.Allow(c, path) { return routing.NewHTTPError(http.StatusNotFound) } var ( file http.File fstat os.FileInfo err error ) if file, err = dir.Open(path); err != nil { if options.CatchAllFile != "" { return serveFile(c, dir, options.CatchAllFile) } return routing.NewHTTPError(http.StatusNotFound, err.Error()) } defer file.Close() if fstat, err = file.Stat(); err != nil { return routing.NewHTTPError(http.StatusNotFound, err.Error()) } if fstat.IsDir() { if options.IndexFile == "" { return routing.NewHTTPError(http.StatusNotFound) } return serveFile(c, dir, filepath.Join(path, options.IndexFile)) } http.ServeContent(c.Response, c.Request, path, fstat.ModTime(), file) return nil } }
func (s *Server) serveGzippedFile(w http.ResponseWriter, r *http.Request, filename string, cache bool) { dir := http.Dir(s.staticPath) var err error var f http.File gzipped := false if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { f, err = dir.Open(filename + ".gz") if err != nil { f = nil } else { gzipped = true } } if f == nil { f, err = dir.Open(filename) if err != nil { http.NotFound(w, r) return } } defer f.Close() d, err := f.Stat() if err != nil { http.NotFound(w, r) return } name := d.Name() if gzipped { name = strings.TrimSuffix(name, ".gz") w = &gzipResponseWriter{ ResponseWriter: w, cache: cache, } } http.ServeContent(w, r, name, d.ModTime(), f) }
// Static returns a handler that serves the files under the specified folder as response content. // For example, if root is "static" and the handler is handling the URL path "/app/index.html", // then the content of the file "<working dir>/static/app/index.html" may be served as the response. func Static(root string, opts ...StaticOptions) Handler { if !filepath.IsAbs(root) { root = filepath.Join(RootPath, root) } options := StaticOptions{} if len(opts) > 0 { options = opts[0] } if options.IndexFile == "" { options.IndexFile = "index.html" } // limit the files to be served within the specified folder dir := http.Dir(root) return func(c *Context) { if c.Request.Method != "GET" && c.Request.Method != "HEAD" { c.Next() return } path := c.Request.URL.Path if options.Prefix != "" { if !strings.HasPrefix(path, options.Prefix) { c.Next() return } path = path[len(options.Prefix):] if path != "" && path[0] != '/' { c.Next() return } } if options.Allow != nil && !options.Allow(c, path) { return } var ( file http.File fstat os.FileInfo err error ) if file, err = dir.Open(path); err != nil { c.Next() return } defer file.Close() if fstat, err = file.Stat(); err != nil { c.Next() return } // if it's a directory, try the index file if fstat.IsDir() { path = filepath.Join(path, options.IndexFile) if file, err = dir.Open(path); err != nil { c.Next() return } defer file.Close() if fstat, err = file.Stat(); err != nil || fstat.IsDir() { c.Next() return } } http.ServeContent(c.Response, c.Request, path, fstat.ModTime(), file) } }