aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mike@crute.us>2023-08-20 09:36:43 -0700
committerMike Crute <mike@crute.us>2023-08-20 09:36:43 -0700
commit37dbd38e00bbe51d1aa2d46bf7a7f454034dd4a2 (patch)
treeb1d1a40a56594d4e7ac2ec8a6655ab57d9d3556a
parentd45bc849d6360b28ddb52ff49c5ef0a694c8a15b (diff)
downloadgolib-37dbd38e00bbe51d1aa2d46bf7a7f454034dd4a2.tar.bz2
golib-37dbd38e00bbe51d1aa2d46bf7a7f454034dd4a2.tar.xz
golib-37dbd38e00bbe51d1aa2d46bf7a7f454034dd4a2.zip
echo: expose error handlerecho/v0.11.2
-rw-r--r--TODO.md1
-rw-r--r--echo/echo_default.go16
-rw-r--r--echo/error_handler.go39
3 files changed, 38 insertions, 18 deletions
diff --git a/TODO.md b/TODO.md
index 4c794cf..ce21a0d 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,2 +1,3 @@
1[ ] Contribute crypto/ocsp/client.go to x/crypto 1[ ] Contribute crypto/ocsp/client.go to x/crypto
2[ ] secrets: add AEAD/AAD method for `associated_data` (base64 encoded) 2[ ] secrets: add AEAD/AAD method for `associated_data` (base64 encoded)
3[ ] echo: nicer HTML error messages (https://github.com/pkg/errors/blob/master/stack.go)
diff --git a/echo/echo_default.go b/echo/echo_default.go
index ff3c754..33ad015 100644
--- a/echo/echo_default.go
+++ b/echo/echo_default.go
@@ -71,9 +71,10 @@ type EchoConfig struct {
71 71
72type EchoWrapper struct { 72type EchoWrapper struct {
73 *echo.Echo 73 *echo.Echo
74 runner *service.AppRunner 74 runner *service.AppRunner
75 autocert autocert.PrimingCertProvider 75 autocert autocert.PrimingCertProvider
76 templateFS fs.FS 76 templateFS fs.FS
77 errorHandler ErrorHandler
77} 78}
78 79
79// NewEchoWrapper creates a new instance of Echo and wraps it in an 80// NewEchoWrapper creates a new instance of Echo and wraps it in an
@@ -132,6 +133,10 @@ func (w *EchoWrapper) GetTemplateFS() fs.FS {
132 return w.templateFS 133 return w.templateFS
133} 134}
134 135
136func (w *EchoWrapper) AddErrorHandler(h ContentErrorHandler, mime ...string) {
137 w.errorHandler.AddHandler(h, mime...)
138}
139
135func (w *EchoWrapper) Configure(c EchoConfig) error { 140func (w *EchoWrapper) Configure(c EchoConfig) error {
136 w.configureAutocert(&c) 141 w.configureAutocert(&c)
137 142
@@ -207,12 +212,13 @@ func (w *EchoWrapper) configureTemplates(c *EchoConfig) error {
207 return fmt.Errorf("Error loading template renderer: %w", err) 212 return fmt.Errorf("Error loading template renderer: %w", err)
208 } 213 }
209 214
210 w.HTTPErrorHandler = NewDefaultErrorHandler(tr).HandleError 215 w.errorHandler = NewDefaultErrorHandler(tr)
211 w.Renderer = tr 216 w.Renderer = tr
212 } else { 217 } else {
213 w.HTTPErrorHandler = NewNoHTMLErrorHandler().HandleError 218 w.errorHandler = NewNoHTMLErrorHandler()
214 } 219 }
215 220
221 w.HTTPErrorHandler = w.errorHandler.HandleError
216 w.templateFS = templates 222 w.templateFS = templates
217 return nil 223 return nil
218} 224}
diff --git a/echo/error_handler.go b/echo/error_handler.go
index 6874eff..a0bdd60 100644
--- a/echo/error_handler.go
+++ b/echo/error_handler.go
@@ -10,17 +10,22 @@ import (
10 "github.com/labstack/echo/v4" 10 "github.com/labstack/echo/v4"
11) 11)
12 12
13// TODO: This should have some kind of HTML formatting of panics in debug mode
14
15type ContentErrorHandler interface { 13type ContentErrorHandler interface {
16 Handle(echo.Context, *echo.HTTPError) error 14 Handle(echo.Context, *echo.HTTPError) error
17} 15}
18 16
17type ErrorHandler interface {
18 AddHandler(ContentErrorHandler, ...string)
19 HandleError(error, echo.Context)
20}
21
19type HTMLErrorHandler struct { 22type HTMLErrorHandler struct {
20 r *TemplateRenderer 23 r *TemplateRenderer
21 fallback *template.Template 24 fallback *template.Template
22} 25}
23 26
27var _ ContentErrorHandler = (*HTMLErrorHandler)(nil)
28
24func NewHTMLErrorHandler(r *TemplateRenderer) *HTMLErrorHandler { 29func NewHTMLErrorHandler(r *TemplateRenderer) *HTMLErrorHandler {
25 t, err := template.New("").Parse("<html><body><h1>Error</h1><pre>{{ .Message }}</pre></body></html>\n") 30 t, err := template.New("").Parse("<html><body><h1>Error</h1><pre>{{ .Message }}</pre></body></html>\n")
26 if err != nil { 31 if err != nil {
@@ -58,12 +63,16 @@ func (h *HTMLErrorHandler) Handle(c echo.Context, e *echo.HTTPError) error {
58 63
59type PlainTextErrorHandler struct{} 64type PlainTextErrorHandler struct{}
60 65
66var _ ContentErrorHandler = (*PlainTextErrorHandler)(nil)
67
61func (h *PlainTextErrorHandler) Handle(c echo.Context, e *echo.HTTPError) error { 68func (h *PlainTextErrorHandler) Handle(c echo.Context, e *echo.HTTPError) error {
62 return c.String(e.Code, fmt.Sprintf("%s", e.Message)) 69 return c.String(e.Code, fmt.Sprintf("%s", e.Message))
63} 70}
64 71
65type JSONErrorHandler struct{} 72type JSONErrorHandler struct{}
66 73
74var _ ContentErrorHandler = (*JSONErrorHandler)(nil)
75
67func (h *JSONErrorHandler) Handle(c echo.Context, e *echo.HTTPError) error { 76func (h *JSONErrorHandler) Handle(c echo.Context, e *echo.HTTPError) error {
68 code := e.Code 77 code := e.Code
69 message := e.Message 78 message := e.Message
@@ -80,28 +89,32 @@ func (h *JSONErrorHandler) Handle(c echo.Context, e *echo.HTTPError) error {
80 89
81type failsafeHandler struct{} 90type failsafeHandler struct{}
82 91
92var _ ContentErrorHandler = (*failsafeHandler)(nil)
93
83func (h *failsafeHandler) Handle(c echo.Context, e *echo.HTTPError) error { 94func (h *failsafeHandler) Handle(c echo.Context, e *echo.HTTPError) error {
84 c.Echo().Logger.Error("Error while processing error page: %s", e) 95 c.Echo().Logger.Error("Error while processing error page: %s", e)
85 c.JSON(http.StatusInternalServerError, e) 96 c.JSON(http.StatusInternalServerError, e)
86 return nil 97 return nil
87} 98}
88 99
89type ErrorHandler struct { 100type EchoErrorHandler struct {
90 types []contenttype.MediaType 101 types []contenttype.MediaType
91 typeMap map[string]ContentErrorHandler 102 typeMap map[string]ContentErrorHandler
92 failsafeHandler ContentErrorHandler 103 failsafeHandler ContentErrorHandler
93} 104}
94 105
95func NewErrorHandler() *ErrorHandler { 106var _ ErrorHandler = (*EchoErrorHandler)(nil)
96 return &ErrorHandler{ 107
108func NewEchoErrorHandler() *EchoErrorHandler {
109 return &EchoErrorHandler{
97 types: []contenttype.MediaType{}, 110 types: []contenttype.MediaType{},
98 typeMap: map[string]ContentErrorHandler{}, 111 typeMap: map[string]ContentErrorHandler{},
99 failsafeHandler: &failsafeHandler{}, 112 failsafeHandler: &failsafeHandler{},
100 } 113 }
101} 114}
102 115
103func NewDefaultErrorHandler(tr *TemplateRenderer) *ErrorHandler { 116func NewDefaultErrorHandler(tr *TemplateRenderer) *EchoErrorHandler {
104 h := NewErrorHandler() 117 h := NewEchoErrorHandler()
105 118
106 // The order of these is important, especially when negotiating */* 119 // The order of these is important, especially when negotiating */*
107 h.AddHandler(&JSONErrorHandler{}, "text/json", "application/json") 120 h.AddHandler(&JSONErrorHandler{}, "text/json", "application/json")
@@ -111,8 +124,8 @@ func NewDefaultErrorHandler(tr *TemplateRenderer) *ErrorHandler {
111 return h 124 return h
112} 125}
113 126
114func NewNoHTMLErrorHandler() *ErrorHandler { 127func NewNoHTMLErrorHandler() *EchoErrorHandler {
115 h := NewErrorHandler() 128 h := NewEchoErrorHandler()
116 129
117 // The order of these is important, especially when negotiating */* 130 // The order of these is important, especially when negotiating */*
118 h.AddHandler(&JSONErrorHandler{}, "text/json", "application/json") 131 h.AddHandler(&JSONErrorHandler{}, "text/json", "application/json")
@@ -121,14 +134,14 @@ func NewNoHTMLErrorHandler() *ErrorHandler {
121 return h 134 return h
122} 135}
123 136
124func (h *ErrorHandler) AddHandler(eh ContentErrorHandler, contentTypes ...string) { 137func (h *EchoErrorHandler) AddHandler(eh ContentErrorHandler, contentTypes ...string) {
125 for _, ct := range contentTypes { 138 for _, ct := range contentTypes {
126 h.types = append(h.types, contenttype.NewMediaType(ct)) 139 h.types = append(h.types, contenttype.NewMediaType(ct))
127 h.typeMap[ct] = eh 140 h.typeMap[ct] = eh
128 } 141 }
129} 142}
130 143
131func (h *ErrorHandler) castToHttpError(e error) *echo.HTTPError { 144func (h *EchoErrorHandler) castToHttpError(e error) *echo.HTTPError {
132 he, ok := e.(*echo.HTTPError) 145 he, ok := e.(*echo.HTTPError)
133 if ok { 146 if ok {
134 if he.Internal != nil { 147 if he.Internal != nil {
@@ -145,7 +158,7 @@ func (h *ErrorHandler) castToHttpError(e error) *echo.HTTPError {
145 } 158 }
146} 159}
147 160
148func (h *ErrorHandler) negotiateContentType(r *http.Request) (ContentErrorHandler, error) { 161func (h *EchoErrorHandler) negotiateContentType(r *http.Request) (ContentErrorHandler, error) {
149 var err error 162 var err error
150 163
151 ct, _, err := contenttype.GetAcceptableMediaType(r, h.types) 164 ct, _, err := contenttype.GetAcceptableMediaType(r, h.types)
@@ -163,7 +176,7 @@ func (h *ErrorHandler) negotiateContentType(r *http.Request) (ContentErrorHandle
163 return handle, err 176 return handle, err
164} 177}
165 178
166func (h *ErrorHandler) HandleError(err error, c echo.Context) { 179func (h *EchoErrorHandler) HandleError(err error, c echo.Context) {
167 defer func() { 180 defer func() {
168 if r := recover(); r != nil { 181 if r := recover(); r != nil {
169 if err, ok := r.(error); !ok { 182 if err, ok := r.(error); !ok {