func readFile(f http.File) (chan *FramebufferUpdate, error) { gzipReader, err := gzip.NewReader(f) if err != nil { return nil, err } bufioReader := bufio.NewReader(gzipReader) reader := NewRecordingReader(bufioReader) output := make(chan *FramebufferUpdate) go func() { defer f.Close() defer close(output) var err error for err == nil { err = readUpdate(reader, output) } if err != nil && err != io.EOF { log.Errorln("error decoding recording:", err) } }() return output, 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) } }