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 }
// OverrideRequestMethod overrides the http // request's method with the specified method. func OverrideRequestMethod(c echo.Context, method string) error { if !isValidOverrideMethod(method) { return ErrInvalidOverrideMethod } c.Request().Header().Set(HeaderHTTPMethodOverride, method) return nil }
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 }
// Index responds with the pprof-formatted profile named by the request. // For example, "/debug/pprof/heap" serves the "heap" profile. // Index responds to a request for "/debug/pprof/" with an HTML page // listing the available profiles. func Index(e echo.Context) { r := e.Request() w := e.Response() if strings.HasPrefix(r.URL().Path(), "/debug/pprof/") { name := strings.TrimPrefix(r.URL().Path(), "/debug/pprof/") if name != "" { handler(name).ServeHTTP(e) return } } profiles := pprof.Profiles() if err := indexTmpl.Execute(w, profiles); err != nil { log.Print(err) } }
// Symbol looks up the program counters listed in the request, // responding with a table mapping program counters to function names. // The package initialization registers it as /debug/pprof/symbol. func Symbol(e echo.Context) { w := e.Response() r := e.Request() w.Header().Set("Content-Type", "text/plain; charset=utf-8") // We have to read the whole POST body before // writing any output. Buffer the output here. var buf bytes.Buffer // We don't know how many symbols we have, but we // do have symbol information. Pprof only cares whether // this number is 0 (no symbols available) or > 0. fmt.Fprintf(&buf, "num_symbols: 1\n") var b *bufio.Reader if r.Method() == "POST" { b = bufio.NewReader(r.Body()) } else { b = bufio.NewReader(strings.NewReader(r.URL().RawQuery())) } for { word, err := b.ReadSlice('+') if err == nil { word = word[0 : len(word)-1] // trim + } pc, _ := strconv.ParseUint(string(word), 0, 64) if pc != 0 { f := runtime.FuncForPC(uintptr(pc)) if f != nil { fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name()) } } // Wait until here to check for err; the last // symbol will have an err because it doesn't end in +. if err != nil { if err != io.EOF { fmt.Fprintf(&buf, "reading request: %v\n", err) } break } } w.Write(buf.Bytes()) }
func (name handler) ServeHTTP(e echo.Context) { w := e.Response() r := e.Request() w.Header().Set("Content-Type", "text/plain; charset=utf-8") debug, _ := strconv.Atoi(r.FormValue("debug")) p := pprof.Lookup(string(name)) if p == nil { w.WriteHeader(404) fmt.Fprintf(w, "Unknown profile: %s\n", name) return } gc, _ := strconv.Atoi(r.FormValue("gc")) if name == "heap" && gc > 0 { runtime.GC() } p.WriteTo(w, debug) return }
// Trace responds with the execution trace in binary form. // Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. // The package initialization registers it as /debug/pprof/trace. func Trace(e echo.Context) { w := e.Response() r := e.Request() sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64) if sec == 0 { sec = 1 } // Set Content Type assuming trace.Start will work, // because if it does it starts writing. w.Header().Set("Content-Type", "application/octet-stream") if err := trace.Start(w); err != nil { // trace.Start failed, so no writes yet. // Can change header back to text content and send error code. w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Could not enable tracing: %s\n", err) return } sleep(e, time.Duration(sec)*time.Second) trace.Stop() }
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 }