func HttpCache(ctx echo.Context, eTag interface{}, etagValidator func(oldEtag, newEtag string) bool) bool { var etag string if eTag == nil { etag = fmt.Sprintf(`%v`, time.Now().UTC().Unix()) } else { etag = fmt.Sprintf(`%v`, eTag) } resp := ctx.Response() //resp.Header().Set(`Connection`, `keep-alive`) resp.Header().Set(`X-Cache`, `HIT from Webx-Page-Cache`) if inm := ctx.Request().Header().Get("If-None-Match"); inm != `` { var valid bool if etagValidator != nil { valid = etagValidator(inm, etag) } else { valid = inm == etag } if valid { resp.Header().Del(`Content-Type`) resp.Header().Del(`Content-Length`) resp.WriteHeader(http.StatusNotModified) ctx.Object().Echo().Logger().Debugf(`%v is not modified.`, ctx.Path()) return true } } resp.Header().Set(`Etag`, etag) resp.Header().Set(`Cache-Control`, `public,max-age=1`) return false }
func (c *Config) Expired(rule *Rule, ctx echo.Context, saveFile string) (int64, bool) { var expired int64 if rule.ExpireTime > 0 { expired = int64(rule.ExpireTime) } else if rule.ExpireFunc != nil { return rule.ExpireFunc(saveFile, ctx) } else { switch c.HtmlCacheTime.(type) { case int: expired = int64(c.HtmlCacheTime.(int)) case int64: expired = c.HtmlCacheTime.(int64) case func(string, echo.Context) (int64, bool): fn := c.HtmlCacheTime.(func(string, echo.Context) (int64, bool)) return fn(saveFile, ctx) } } mtime, err := com.FileMTime(saveFile) if err != nil { ctx.Object().Echo().Logger().Debug(err) } if mtime == 0 { return mtime, true } if time.Now().Local().Unix() > mtime+expired { return mtime, true } return mtime, false }
func (c *Config) Write(b []byte, ctx echo.Context) bool { if !c.HtmlCacheOn || ctx.Request().Method() != `GET` || X.X(ctx).Code != http.StatusOK { return false } tmpl := X.MustString(ctx, `webx:saveHtmlFile`) if tmpl == `` { return false } if err := com.WriteFile(tmpl, b); err != nil { ctx.Object().Echo().Logger().Debug(err) } return true }
func (c *Config) Read(ctx echo.Context) bool { ct := X.X(ctx) req := ctx.Request() if !c.HtmlCacheOn || req.Method() != `GET` { return false } p := strings.Trim(req.URL().Path(), `/`) if p == `` { p = `index` } s := strings.SplitN(p, `/`, 3) if c.htmlCacheRules == nil { c.htmlCacheRules = make(map[string]*Rule) for key, rule := range c.HtmlCacheRules { c.htmlCacheRules[key] = c.Rule(rule) } } var rule *Rule switch len(s) { case 2: k := s[0] + `:` + s[1] if v, ok := c.htmlCacheRules[k]; ok { rule = v } else if v, ok := c.htmlCacheRules[s[1]]; ok { rule = v } else { k = s[0] + `:` if v, ok := c.htmlCacheRules[k]; ok { rule = v } } case 1: k := s[0] + `:` if v, ok := c.htmlCacheRules[k]; ok { rule = v } } var saveFile string = c.SaveFileName(rule, ctx) if saveFile == "" { return false } if ct.Format != `` { saveFile += `.` + ct.Format } mtime, expired := c.Expired(rule, ctx, saveFile) if expired { ctx.Set(`webx:saveHtmlFile`, saveFile) return false } //_ = mtime //ctx.File(saveFile, ``, false) if !HttpCache(ctx, mtime, nil) { html, err := com.ReadFile(saveFile) if err != nil { ctx.Object().Echo().Logger().Error(err) } Output(html, ct) } ct.Exit = true return true }