diff --git a/errorCatcher.go b/errorCatcher.go new file mode 100644 index 0000000..495fe9e --- /dev/null +++ b/errorCatcher.go @@ -0,0 +1,74 @@ +package main + +import ( + "net/http" + "strconv" + + "github.com/aymerick/raymond" +) + +// errorCatcher is a wrapper for http.ResponseWriter that +// captures 4xx and 5xx status codes and handles them in +// a custom manner +type errorCatcher struct { + req *http.Request + res http.ResponseWriter + errorTpl *raymond.Template + notFoundTpl *raymond.Template + handledError bool +} + +func (ec *errorCatcher) Header() http.Header { + return ec.res.Header() +} + +func (ec *errorCatcher) Write(buf []byte) (int, error) { + // if we have already sent a response, pretend that this was successful + if ec.handledError { + return len(buf), nil + } + return ec.res.Write(buf) +} + +func (ec *errorCatcher) WriteHeader(statusCode int) { + if ec.handledError { + return + } + if statusCode == 404 { + ctx := map[string]string{ + "path": ec.req.URL.Path, + } + page, err := ec.notFoundTpl.Exec(ctx) + // if we don't have a page to write, return before + // we toggle the flag so we fall back to the original + // error page + if err != nil { + return + } + ec.res.Header().Add("content-type", "text/html") + ec.res.WriteHeader(statusCode) + ec.res.Write([]byte(page)) + ec.handledError = true + return + } + + if statusCode >= 400 && statusCode < 600 { + ctx := map[string]string{ + "code": strconv.Itoa(statusCode), + } + page, err := ec.errorTpl.Exec(ctx) + // if we don't have a page to write, return before + // we toggle the flag so we fall back to the original + // error page + if err != nil { + return + } + ec.res.Header().Add("content-type", "text/html") + ec.res.WriteHeader(statusCode) + ec.res.Write([]byte(page)) + ec.handledError = true + return + } + + ec.res.WriteHeader(statusCode) +} diff --git a/server.go b/server.go index cb90ddc..ce637ed 100644 --- a/server.go +++ b/server.go @@ -19,6 +19,8 @@ type server struct { pageTpl *raymond.Template fullPostTpl *raymond.Template summaryTpl *raymond.Template + errorTpl *raymond.Template + notFoundTpl *raymond.Template } func newServer() (*server, error) { @@ -81,6 +83,18 @@ func (s *server) refreshTemplates() error { } log.Printf("Loaded full post template") + s.notFoundTpl, err = raymond.ParseFile("templates/notfound.html") + if err != nil { + return fmt.Errorf("could not parse 404 template") + } + log.Printf("Loaded 404 template") + + s.errorTpl, err = raymond.ParseFile("templates/error.html") + if err != nil { + return fmt.Errorf("could not parse error template") + } + log.Printf("Loaded error template") + s.summaryTpl, err = raymond.ParseFile("templates/summary.html") if err != nil { return fmt.Errorf("could not parse summary template") @@ -138,6 +152,13 @@ func (s *server) logRequest(req *http.Request) { func (s *server) router(res http.ResponseWriter, req *http.Request) { s.logRequest(req) + res = &errorCatcher{ + res: res, + req: req, + errorTpl: s.errorTpl, + notFoundTpl: s.notFoundTpl, + handledError: false, + } slug := req.URL.Path[1:] if slug == "" { diff --git a/styles/error.css b/styles/error.css new file mode 100644 index 0000000..92df3a3 --- /dev/null +++ b/styles/error.css @@ -0,0 +1,11 @@ +body { + font-family: monospace; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + margin: 0; + min-height: 100vh; + font-size: 20px; + text-align: center; +} \ No newline at end of file diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..8cc9c2e --- /dev/null +++ b/templates/error.html @@ -0,0 +1,16 @@ + + +
+ + + +Calm down. Take a deep breath. Error {{code}}s can happen to anyone. Seriously. It's alright.
+ +Try again in a while, or check out my website, which should not have these issues. Probably.
+ + diff --git a/templates/notfound.html b/templates/notfound.html new file mode 100644 index 0000000..ecd573c --- /dev/null +++ b/templates/notfound.html @@ -0,0 +1,17 @@ + + + + + + +Haha, just kidding. No, but really, there's no page here. This is what the kids call an “Error 404” situation.
+ +Consider visiting my homepage, which is guaranteed to exist.
+ + +