You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

58 lines
1.6 KiB

  1. package handlers
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. // Augmented response writer to hold the panic data (can be anything, not necessarily an error
  7. // interface).
  8. type errResponseWriter struct {
  9. http.ResponseWriter
  10. perr interface{}
  11. }
  12. // Implement the WrapWriter interface.
  13. func (this *errResponseWriter) WrappedWriter() http.ResponseWriter {
  14. return this.ResponseWriter
  15. }
  16. // PanicHandlerFunc is the same as PanicHandler, it is just a convenience
  17. // signature that accepts a func(http.ResponseWriter, *http.Request) instead of
  18. // a http.Handler interface. It saves the boilerplate http.HandlerFunc() cast.
  19. func PanicHandlerFunc(h http.HandlerFunc, errH http.HandlerFunc) http.HandlerFunc {
  20. return PanicHandler(h, errH)
  21. }
  22. // Calls the wrapped handler and on panic calls the specified error handler. If the error handler is nil,
  23. // responds with a 500 error message.
  24. func PanicHandler(h http.Handler, errH http.Handler) http.HandlerFunc {
  25. return func(w http.ResponseWriter, r *http.Request) {
  26. defer func() {
  27. if err := recover(); err != nil {
  28. if errH != nil {
  29. ew := &errResponseWriter{w, err}
  30. errH.ServeHTTP(ew, r)
  31. } else {
  32. http.Error(w, fmt.Sprintf("%s", err), http.StatusInternalServerError)
  33. }
  34. }
  35. }()
  36. // Call the protected handler
  37. h.ServeHTTP(w, r)
  38. }
  39. }
  40. // Helper function to retrieve the panic error, if any.
  41. func GetPanicError(w http.ResponseWriter) (interface{}, bool) {
  42. er, ok := GetResponseWriter(w, func(tst http.ResponseWriter) bool {
  43. _, ok := tst.(*errResponseWriter)
  44. return ok
  45. })
  46. if ok {
  47. return er.(*errResponseWriter).perr, true
  48. }
  49. return nil, false
  50. }