func (m *Manager) scanFile(path string) (*file, error) { f := &file{ fullpath: filepath.Join(m.cfg.Path, path), } fh, err := vfs.Open(f.fullpath) if err != nil { log.Debuge(err, "cannot find asset with path: ", f.fullpath) return f, nil } defer fh.Close() fi, err := fh.Stat() if err != nil { log.Debuge(err, "stat") return f, nil } f.mtime = fi.ModTime() h := sha256.New() _, err = io.Copy(h, fh) if err != nil { log.Debuge(err, "copy") return f, nil } hash := h.Sum(nil) f.sha256 = hash f.tag = base64.RawURLEncoding.EncodeToString(f.sha256) //f.tag = timeToTag(f.mtime) return f, nil }
// Serve static files from assets. func (m *Manager) TryHandle(rw http.ResponseWriter, req *http.Request) error { if req.Method != "GET" && req.Method != "HEAD" { return ErrUnsupportedMethod } path, cachebuster := stripCachebuster(req.URL.Path) // "/img/x.png", "foobar" info := m.Info(path[1:]) if info == nil { // May as well not bother with anything the asset manager can't find. The // asset manager ensures that the final path is within the static root. return ErrNotFound } fpath := info.FullPath() f, err := vfs.Open(fpath) if err != nil { return err } defer f.Close() rw.Header().Set("Vary", "Accept-Encoding") if cachebuster != "" { // At some point we should probably check this to prevent cache poisoning // but it will break long-expiry for resources referenced from CSS files // since they will be in the same cachebuster 'directory' and thus have the // wrong tag. Alternatively, could move to unpredictable tags (ones not // based on modification tags.) // && cachebuster == info.Tag() { rw.Header().Set("Expires", time.Now().Add(28*24*time.Hour).UTC().Format(time.RFC1123)) rw.Header().Set("Cache-Control", "public, max-age=2419200") } // Currently, disable CSP for assets under the assumption that they are safe // and trusted. This is unfortunately necessary because some served SVG files // have inline SVG, and externalizing it would be quite overkill. rw.Header().Del("Content-Security-Policy") rw.Header().Del("Content-Security-Policy-Report-Only") http.ServeContent(rw, req, fpath, info.ModTime(), f) return nil }
// Load all templates from the given directory. The templates must have the file extension ".p2". func LoadTemplates(dirname string) error { err := binarc.Setup(opts.BaseDir) if err != nil { return err } pongo2.OpenFunc = func(name string) (io.ReadCloser, error) { return vfs.Open(name) } c, err := loadTemplates(dirname) if err != nil { return err } for k, v := range c { templates[k] = v } return nil }
func loadTemplates(dirname string) (map[string]*pongo2.Template, error) { dir, err := vfs.Open(dirname) if err != nil { return nil, err } defer dir.Close() files, err := dir.Readdir(0) if err != nil { return nil, err } compiled := make(map[string]*pongo2.Template) for _, f := range files { fn := f.Name() fext := filepath.Ext(fn) path := filepath.Join(dirname, fn) if f.IsDir() { subcompiled, err := loadTemplates(path) if err != nil { return nil, err } for k, v := range subcompiled { compiled[filepath.Join(fn, k)] = v } } else if fext == ".p2" { tpl, err := pongo2.FromFile(path) if err != nil { return nil, err } k := fn[0 : len(fn)-len(fext)] compiled[k] = tpl } } return compiled, nil }