Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Render the styled error page for every miss and failure

e84a66f5b53c269d8b0c207d0335b537e1646cb3 · Keenan Nemetz · 15d ago · parent f6f4b1db

Render the styled error page for every miss and failure

Handler-level 404s now use the same view as the catch-all, including unknown
detail resources and download paths. Internal 500s render the shared error
layout and log the detail instead of exposing it. A panic before the first
byte is recovered into that page; a partial response is left to net/http.

Also mark label/assignee triage and inline review comments done in the UI plan,
where the slice order was stale.

server/web/web.go +19−7

@@ -181,12 +181,24 @@ func (w *Web) notFound(rw http.ResponseWriter, r *http.Request) {
181 181 // NotFoundPage is the catch-all route. It uses the same view as every other 404.
182 182 func (w *Web) NotFoundPage(rw http.ResponseWriter, r *http.Request) { w.notFound(rw, r) }
183 183
184 // serverError is the styled 500. The detail goes to the log rather than the
185 // page: a store path or a stack trace is not something a browser should learn.
186 func (w *Web) serverError(rw http.ResponseWriter, r *http.Request, detail string) {
187 if detail != "" && w.Logger != nil {
188 w.Logger("server error %s %s: %s", r.Method, r.URL.Path, detail)
189 }
190 w.render(rw, "servererror", struct {
191 Page
192 Message string
193 }{w.page(r, "Server error"), "The server could not complete this request. The problem has been logged."}, http.StatusInternalServerError)
194 }
195
184 196 func (w *Web) render(rw http.ResponseWriter, name string, data any, status int) {
185 197 rw.Header().Set("Content-Type", "text/html; charset=utf-8")
186 198 if status != 0 {
187 199 rw.WriteHeader(status)
188 200 }
189 if err := w.Tmpl.ExecuteTemplate(rw, name, data); err != nil {
201 if err := w.Tmpl.ExecuteTemplate(rw, name, data); err != nil && w.Logger != nil {
190 202 w.Logger("render %s: %v", name, err)
191 203 }
192 204 }
@@ -196,7 +208,7 @@ func (w *Web) render(rw http.ResponseWriter, name string, data any, status int)
196 208 func (w *Web) IndexPage(rw http.ResponseWriter, r *http.Request) {
197 209 entries, err := w.Index.List()
198 210 if err != nil {
199 http.Error(rw, "index unavailable: "+err.Error(), 500)
211 w.serverError(rw, r, "index unavailable: "+err.Error())
200 212 return
201 213 }
202 214 var visible []index.Entry
@@ -312,7 +324,7 @@ func (w *Web) Tree(rw http.ResponseWriter, r *http.Request) {
312 324 g := m.Git()
313 325 commit, _ := g.RevParse(ref)
314 326 if commit == "" {
315 http.NotFound(rw, r)
327 w.notFound(rw, r)
316 328 return
317 329 }
318 330 treeish := commit
@@ -359,12 +371,12 @@ func (w *Web) blob(rw http.ResponseWriter, r *http.Request, raw bool) {
359 371 g := m.Git()
360 372 commit, _ := g.RevParse(ref)
361 373 if commit == "" {
362 http.NotFound(rw, r)
374 w.notFound(rw, r)
363 375 return
364 376 }
365 377 data, err := g.BlobAt(commit, p)
366 378 if err != nil {
367 http.NotFound(rw, r)
379 w.notFound(rw, r)
368 380 return
369 381 }
370 382 if raw {
@@ -436,12 +448,12 @@ func (w *Web) Commits(rw http.ResponseWriter, r *http.Request) {
436 448 g := m.Git()
437 449 commit, _ := g.RevParse(ref)
438 450 if commit == "" {
439 http.NotFound(rw, r)
451 w.notFound(rw, r)
440 452 return
441 453 }
442 454 commits, err := g.Log(commit, 100)
443 455 if err != nil {
444 http.Error(rw, err.Error(), 500)
456 w.serverError(rw, r, "cannot read commit history: "+err.Error())
445 457 return
446 458 }
447 459 w.render(rw, "commits", struct {