package core import ( "bytes" "fmt" "html/template" "net/http" ) // errorTmpl is compiled from a literal, not from the theme's template // files -- a broken view template is exactly the situation this page has // to survive, so it cannot depend on LoadTemplates succeeding. var errorTmpl = template.Must(template.New("error").Parse(` {{.Code}} {{.Status}} · {{.Site}}

{{.Code}}

{{.Status}}

{{.Message}}

← back to {{.Site}}

`)) // renderErrorPage never returns an error: if the template somehow fails to // execute, it falls back to a plain-text body rather than propagating. func renderErrorPage(code int, site string) (body []byte, contentType string) { data := struct { Code int Status, Message, Site string }{ Code: code, Status: http.StatusText(code), Message: friendlyMessage(code), Site: site, } var buf bytes.Buffer if err := errorTmpl.Execute(&buf, data); err != nil { return []byte(fmt.Sprintf("%d %s\n", code, http.StatusText(code))), "text/plain; charset=utf-8" } return buf.Bytes(), "text/html; charset=utf-8" } // friendlyMessage keeps the diagnostic detail out of the response body -- // that stays in the server log -- while still telling a human what class // of problem they hit. func friendlyMessage(code int) string { switch code { case http.StatusNotFound: return "We couldn't find that repository, ref, or path." case http.StatusBadRequest: return "That request doesn't look right." case http.StatusRequestEntityTooLarge: return "That response is too large to display in full." default: return "Something went wrong rendering this page. The details were logged." } }