all repos — homestead @ 63e8b92d6e764cac748e1a97d88698e93b8ffafa

Code for my website

use builtin error interface for http handlers

Alan Pearce
commit

63e8b92d6e764cac748e1a97d88698e93b8ffafa

parent

f58148583a563fca788c4dc9c357a3d2d6e0f49c

M domain/content/publisher/mux.godomain/content/publisher/mux.go
@@ -31,7 +31,7 @@ ErrCannotDetermineUser = ihttp.NewError("cannot determine user", http.StatusInternalServerError)
ErrRenderFailure = ihttp.NewError("failed to render page", http.StatusInternalServerError) ) -func (s *Service) Index(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (s *Service) Index(w http.ResponseWriter, r *http.Request) error { userName := "Guest" isLoggedIn := false if user, err := getUserFromRequest(r); err == nil {
@@ -62,7 +62,7 @@ // Login initiates the OIDC authentication flow with PKCE S256.
// PKCE (Proof Key for Code Exchange) protects against authorization code interception attacks // by using a cryptographically random verifier and its SHA256 hash challenge. // See: https://www.rfc-editor.org/rfc/rfc7636 -func (s *Service) Login(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (s *Service) Login(w http.ResponseWriter, r *http.Request) error { // Generate random state for CSRF protection state, err := generateRandomState() if err != nil {
@@ -106,7 +106,7 @@
// Callback handles the OIDC provider's redirect after authentication. // It verifies the state parameter (CSRF protection), exchanges the authorization code // for tokens using the PKCE verifier, validates the ID token, and creates a session. -func (s *Service) Callback(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (s *Service) Callback(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() // Verify state parameter (CSRF protection)
@@ -212,7 +212,7 @@
return nil } -func (s *Service) Logout(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (s *Service) Logout(w http.ResponseWriter, r *http.Request) error { // Clear session cookie http.SetCookie(w, &http.Cookie{ Name: sessionCookieName,
@@ -263,7 +263,7 @@
return base64.URLEncoding.EncodeToString(b), nil } -func (s *Service) Style(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (s *Service) Style(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Content-Type", "text/css") http.ServeFileFS(w, r, basetpl.Files, "style.css")
M domain/identity/webfinger/service.godomain/identity/webfinger/service.go
@@ -59,7 +59,7 @@ func (s *Service) RegisterHandlers(mux *ihttp.ServeMux) {
mux.HandleFunc("/.well-known/webfinger", s.HandleFunc) } -func (s *Service) HandleFunc(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (s *Service) HandleFunc(w http.ResponseWriter, r *http.Request) error { resource := r.URL.Query().Get("resource") if resource == "" { return ErrMissingResourceParameter
M domain/web/mux.godomain/web/mux.go
@@ -26,19 +26,23 @@ "Access-Control-Max-Age": "3600",
} ) -func (website *Website) ErrorHandler(err ihttp.Error, w http.ResponseWriter, r *http.Request) { +func (website *Website) ErrorHandler(err error, w http.ResponseWriter, r *http.Request) { + hErr, ok := err.(ihttp.Error) + if !ok { + hErr = ihttp.NewError(err.Error(), http.StatusInternalServerError) + } if strings.Contains(r.Header.Get("Accept"), "text/html") { - w.WriteHeader(err.StatusCode()) - err := templates.Error(*website.siteSettings, err).Render(w) + w.WriteHeader(hErr.StatusCode()) + err := templates.Error(*website.siteSettings, hErr).Render(w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } else { - http.Error(w, err.Error(), err.StatusCode()) + http.Error(w, hErr.Error(), hErr.StatusCode()) } } -func (website *Website) ServeHTTP(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (website *Website) ServeHTTP(w http.ResponseWriter, r *http.Request) error { urlPath := r.URL.Path if r.URL.Query().Has("go-get") && r.URL.Query().Get("go-get") == "1" { urlPath = "/go" + r.URL.Path
@@ -80,7 +84,7 @@
return nil } -func (website *Website) Calendar(w http.ResponseWriter, r *http.Request) ihttp.Error { +func (website *Website) Calendar(w http.ResponseWriter, r *http.Request) error { analytics.WithTitle(r, "Calendar") err := calendar.CalendarPage(*website.siteSettings, website.calendar).Render(w) if err != nil {
@@ -98,7 +102,7 @@ re := regexp.MustCompile(
"^(.*)\\." + strings.ReplaceAll(website.config.WildcardDomain, ".", `\.`) + "$", ) replace := "${1}." + website.config.Domains[0] - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) ihttp.Error { + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) error { switch { case r.URL.Query().Has("go-get") && r.URL.Query().Get("go-get") == "1": return website.ServeHTTP(w, r)
M domain/web/website.godomain/web/website.go
@@ -189,7 +189,7 @@ website.publisher.RegisterHandlers(mux)
} if opts.Development { - staticHandler := func(w http.ResponseWriter, r *http.Request) ihttp.Error { + staticHandler := func(w http.ResponseWriter, r *http.Request) error { http.ServeFileFS(w, r, templates.Files, r.URL.Path) return nil
M shared/http/mux.goshared/http/mux.go
@@ -7,15 +7,15 @@ "alin.ovh/x/log"
) // HandleFunc is a function that handles an HTTP request and may return an Error. -type HandleFunc func(http.ResponseWriter, *http.Request) Error +type HandleFunc func(http.ResponseWriter, *http.Request) error // Handler is an interface for types that can serve HTTP requests and may return an Error. type Handler interface { - ServeHTTP(http.ResponseWriter, *http.Request) Error + ServeHTTP(http.ResponseWriter, *http.Request) error } // ErrorHandler is a function that handles HTTP errors. -type ErrorHandler func(Error, http.ResponseWriter, *http.Request) +type ErrorHandler func(error, http.ResponseWriter, *http.Request) // ServeMux is an HTTP request multiplexer with error handling support. // It matches the URL of each incoming request against a list of registered
@@ -31,8 +31,12 @@ func NewServeMux(logger *log.Logger) *ServeMux {
return &ServeMux{ ServeMux: http.NewServeMux(), log: logger, - errorHandler: func(err Error, w http.ResponseWriter, _ *http.Request) { - http.Error(w, err.Error(), err.StatusCode()) + errorHandler: func(err error, w http.ResponseWriter, _ *http.Request) { + if hErr, ok := err.(Error); ok { + http.Error(w, hErr.Error(), hErr.StatusCode()) + } else { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } }, } }