func Recover() tango.HandlerFunc { return func(ctx *tango.Context) { defer func() { if e := recover(); e != nil { header := fmt.Sprintf("%v", e) content := "Handler crashed with error:" + header for i := 1; ; i += 1 { _, file, line, ok := runtime.Caller(i) if !ok { break } else { content += "\n" } content += fmt.Sprintf("%v %v", file, line) } p := ctx.Req().URL.Path if len(ctx.Req().URL.RawQuery) > 0 { p = p + "?" + ctx.Req().URL.RawQuery } if !ctx.Written() { ctx.Result = tango.InternalServerError(content) ctx.HandleError() } log15.Error( fmt.Sprintf(logFormat, ctx.Req().Method, ctx.Status(), ctx.Req().URL.Path), "path", p, "remote", ctx.Req().RemoteAddr, "error", header, ) core.Crash.Error( fmt.Sprintf(logFormat, ctx.Req().Method, ctx.Status(), ctx.Req().URL.Path), "path", p, "remote", ctx.Req().RemoteAddr, "error", header, ) } }() ctx.Next() } }
// recovery middleware handler func Recovery(debug bool) tango.HandlerFunc { return func(ctx *tango.Context) { defer func() { if e := recover(); e != nil { content := fmt.Sprintf("Handler crashed with error: %v", e) for i := 1; ; i += 1 { _, file, line, ok := runtime.Caller(i) if !ok { break } else { content += "\n" } content += fmt.Sprintf("%v %v", file, line) } //ctx.Logger.Error(content) if !ctx.Written() { if !debug { content = http.StatusText(http.StatusInternalServerError) } ctx.Result = tango.InternalServerError(content) if render, ok := ctx.Action().(IRender); ok { render.RenderError(http.StatusInternalServerError, errors.New(content)) return } ctx.HandleError() } } }() ctx.Next() } }
// Handle implements tango handler, // copy from tango static.go func (s *Static) Handle(ctx *tango.Context) { if ctx.Req().Method != "GET" && ctx.Req().Method != "HEAD" { ctx.Next() return } opt := prepareStaticOptions(s.Options) var rPath = ctx.Req().URL.Path // if defined prefix, then only check prefix if opt.Prefix != "" { if !strings.HasPrefix(ctx.Req().URL.Path, opt.Prefix) { ctx.Next() return } else { if len(opt.Prefix) == len(ctx.Req().URL.Path) { rPath = "" } else { rPath = ctx.Req().URL.Path[len(opt.Prefix):] } } } fPath, _ := filepath.Abs(filepath.Join(opt.RootPath, rPath)) finfo, err := os.Stat(fPath) if err != nil { if !os.IsNotExist(err) { ctx.Result = tango.InternalServerError(err.Error()) ctx.HandleError() return } } else if !finfo.IsDir() { if len(opt.FilterExts) > 0 { var matched bool for _, ext := range opt.FilterExts { if filepath.Ext(fPath) == ext { matched = true break } } if !matched { ctx.Next() return } } err := ctx.ServeFile(fPath) if err != nil { ctx.Result = tango.InternalServerError(err.Error()) ctx.HandleError() } return } else { // try serving index.html or index.htm if len(opt.IndexFiles) > 0 { for _, index := range opt.IndexFiles { nPath := filepath.Join(fPath, index) finfo, err = os.Stat(nPath) if err != nil { if !os.IsNotExist(err) { ctx.Result = tango.InternalServerError(err.Error()) ctx.HandleError() return } } else if !finfo.IsDir() { err = ctx.ServeFile(nPath) if err != nil { ctx.Result = tango.InternalServerError(err.Error()) ctx.HandleError() } return } } } // list dir files if opt.ListDir { ctx.Header().Set("Content-Type", "text/html; charset=UTF-8") ctx.Write([]byte(`<ul style="list-style-type:none;line-height:32px;">`)) rootPath, _ := filepath.Abs(opt.RootPath) rPath, _ := filepath.Rel(rootPath, fPath) if fPath != rootPath { ctx.Write([]byte(`<li> <a href="/` + path.Join(opt.Prefix, filepath.Dir(rPath)) + `">..</a></li>`)) } err = filepath.Walk(fPath, func(p string, fi os.FileInfo, err error) error { rPath, _ := filepath.Rel(fPath, p) if rPath == "." || len(strings.Split(rPath, string(filepath.Separator))) > 1 { return nil } rPath, _ = filepath.Rel(rootPath, p) ps, _ := os.Stat(p) if ps.IsDir() { ctx.Write([]byte(`<li>┖ <a href="/` + path.Join(opt.Prefix, rPath) + `">` + filepath.Base(p) + `</a></li>`)) } else { if len(opt.FilterExts) > 0 { var matched bool for _, ext := range opt.FilterExts { if filepath.Ext(p) == ext { matched = true break } } if !matched { return nil } } ctx.Write([]byte(`<li> <a href="/` + path.Join(opt.Prefix, rPath) + `">` + filepath.Base(p) + `</a></li>`)) } return nil }) ctx.Write([]byte("</ul>")) return } } }