package httptreemux import ( "bufio" "encoding/json" "html/template" "net/http" "os" "runtime" "strings" ) // SimplePanicHandler just returns error 500. func SimplePanicHandler(w http.ResponseWriter, r *http.Request, err interface{}) { w.WriteHeader(http.StatusInternalServerError) } // ShowErrorsPanicHandler prints a nice representation of an error to the browser. // This was taken from github.com/gocraft/web, which adapted it from the Traffic project. func ShowErrorsPanicHandler(w http.ResponseWriter, r *http.Request, err interface{}) { const size = 4096 stack := make([]byte, size) stack = stack[:runtime.Stack(stack, false)] renderPrettyError(w, r, err, stack) } func makeErrorData(r *http.Request, err interface{}, stack []byte, filePath string, line int) map[string]interface{} { data := map[string]interface{}{ "Stack": string(stack), "Params": r.URL.Query(), "Method": r.Method, "FilePath": filePath, "Line": line, "Lines": readErrorFileLines(filePath, line), } if e, ok := err.(error); ok { data["Error"] = e.Error() } else { data["Error"] = err } return data } func renderPrettyError(rw http.ResponseWriter, req *http.Request, err interface{}, stack []byte) { _, filePath, line, _ := runtime.Caller(5) data := makeErrorData(req, err, stack, filePath, line) rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusInternalServerError) tpl := template.Must(template.New("ErrorPage").Parse(panicPageTpl)) tpl.Execute(rw, data) } func ShowErrorsJsonPanicHandler(w http.ResponseWriter, r *http.Request, err interface{}) { const size = 4096 stack := make([]byte, size) stack = stack[:runtime.Stack(stack, false)] _, filePath, line, _ := runtime.Caller(4) data := makeErrorData(r, err, stack, filePath, line) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(data) } func readErrorFileLines(filePath string, errorLine int) map[int]string { lines := make(map[int]string) file, err := os.Open(filePath) if err != nil { return lines } defer file.Close() reader := bufio.NewReader(file) currentLine := 0 for { line, err := reader.ReadString('\n') if err != nil || currentLine > errorLine+5 { break } currentLine++ if currentLine >= errorLine-5 { lines[currentLine] = strings.Replace(line, "\n", "", -1) } } return lines } const panicPageTpl string = `
{{ .Error }}
In {{ .FilePath }}:{{ .Line }}
{{ range $lineNumber, $line := .Lines }}{{ $lineNumber }}{{ end }}
|
{{ range $lineNumber, $line := .Lines }}{{ $line }}
|
{{ .Stack }}
Method: {{ .Method }}