Created
September 4, 2015 22:38
-
-
Save stroborobo/3fa97a3151cd99ca5fd4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package handlers | |
import ( | |
"fmt" | |
"net/http" | |
"runtime" | |
) | |
// HandlerFunc is the function signature for use in Handler | |
type HandlerFunc func(c *Context, wr http.ResponseWriter, req *http.Request) (string, error) | |
// Handler encapsulates our handlers so we can pass a type save context and | |
// still conform to the http.Handler interface | |
type Handler struct { | |
*Context | |
Func HandlerFunc | |
} | |
// ServeHTTP gets the request context, calls the actual handler func and | |
// handles it's returned error, if any | |
func (h Handler) ServeHTTP(wr http.ResponseWriter, req *http.Request) { | |
c := RequestContext(h.Context, wr, req) | |
// catch handler panics | |
defer func() { | |
r := recover() | |
if r == nil { | |
return | |
} | |
// stack (copied from net/http/server.go:1284) | |
const size = 64 << 10 | |
buf := make([]byte, size) | |
buf = buf[:runtime.Stack(buf, false)] | |
c.Logger.Errorf("panic recovered: %v\n%s", r, buf) | |
c.Metrics.Panics.Inc() | |
http.Error(c.Wr, errInternalServerError.Error(), http.StatusInternalServerError) | |
}() | |
// run the actual handler | |
tpl, origErr := h.Func(c, wr, req) | |
// if there's no error, write 200 OK and display the template if any | |
if origErr == nil { | |
wr.WriteHeader(200) | |
if tpl != "" { | |
h.handleErr(c, c.View.Display(wr, tpl), false) | |
} | |
return | |
} | |
// otherwise handle that motherfucker | |
de := NewDebugError(origErr) | |
err := de.Underlying() | |
if tpl == "" { | |
wr.Header().Set("Content-Type", "text/plain; charset=utf-8") | |
} | |
switch e := err.(type) { | |
case Redirector: | |
http.Redirect(wr, req, e.Path(), e.Status()) | |
return | |
case *UserError: | |
wr.WriteHeader(e.Status()) | |
if tpl == "" { | |
fmt.Fprint(wr, e) | |
} else { | |
c.View.AddError(e) | |
} | |
case Error: | |
c.Logger.Errorf("Status: %d - %v", e.Status(), de) | |
wr.WriteHeader(e.Status()) | |
if tpl == "" { | |
fmt.Fprint(wr, e) | |
} else { | |
c.View.AddError(e) | |
} | |
default: | |
wr.WriteHeader(http.StatusInternalServerError) | |
h.handleErr(c, de, tpl != "") | |
} | |
if tpl == "" { | |
return | |
} | |
h.handleErr(c, c.View.Display(wr, tpl), false) | |
} | |
func (h Handler) handleErr(c *Context, err error, inView bool) { | |
if err == nil { | |
return | |
} | |
err = NewDebugError(err) | |
if inView { | |
c.Logger.Error(err) | |
if c.Debug { | |
c.View.AddError(err) | |
} else { | |
c.View.AddError(errInternalServerError) | |
} | |
} else { | |
c.Logger.Error(err) | |
http.Error(c.Wr, errInternalServerError.Error(), http.StatusInternalServerError) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment