oficina / calendar Public

Render unmatched Calendar routes with existing error page

Co-Authored-By: Codex <noreply@openai.com>
Paul Campbell pushed by paul@keymail.dev b1be7ae117c7c28659bf3bdc17cd81ca2ddd55a3 parent 040eb25
2 files changed, +57 −0
  • internal/calendar/routes.go +4 −0
  • internal/calendartest/notfound_test.go +53 −0

CI failed — run details

diff --git a/internal/calendar/routes.go b/internal/calendar/routes.go
index 7e128d9..2c60129 100644
--- a/internal/calendar/routes.go
+++ b/internal/calendar/routes.go
@@ -26,6 +26,10 @@ func (a *App) routes(h *handlers, authPlugin *rauth.Auth, list allowlist, origin
// covered. Origin-checking, not tokens — nothing to mint or forget
// in a form.
r.Use(csrf.Protect(origin))
+ r.NotFound(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ ErrorPage(w, r, http.StatusNotFound, "")
+ })
// Signed-out.
r.Get("/signin", h.signin)
diff --git a/internal/calendartest/notfound_test.go b/internal/calendartest/notfound_test.go
new file mode 100644
index 0000000..ca17d51
--- /dev/null
+++ b/internal/calendartest/notfound_test.go
@@ -0,0 +1,53 @@
+package calendartest
+
+import (
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestUnknownRouteRendersSharedErrorPage(t *testing.T) {
+ server := httptest.NewServer(newApp(t).Handler())
+ defer server.Close()
+ response, err := server.Client().Get(server.URL + "/not-a-real-route")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer response.Body.Close()
+ body, err := io.ReadAll(response.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if response.StatusCode != http.StatusNotFound {
+ t.Fatalf("status %d", response.StatusCode)
+ }
+ if got := response.Header.Get("Content-Type"); got != "text/html; charset=utf-8" {
+ t.Errorf("content type %q", got)
+ }
+ for _, marker := range []string{"<html", "<main", "rst-error-status>404", "rst-error-title", "/static/theme.", "href=\"/\""} {
+ if !strings.Contains(string(body), marker) {
+ t.Errorf("missing shared error marker %q", marker)
+ }
+ }
+}
+
+func TestNotFoundLeavesMatchedRoutesAlone(t *testing.T) {
+ h := newApp(t).Handler()
+ for _, path := range []string{"/static/not-a-real-file.css", "/feed/not-a-real-token.ics"} {
+ r := get(t, h, path)
+ if r.Code != http.StatusNotFound || r.Body.String() != "404 page not found\n" {
+ t.Errorf("matched refusal changed for %s: status %d", path, r.Code)
+ }
+ if r.Header().Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Errorf("matched refusal type changed for %s", path)
+ }
+ }
+ for _, path := range []string{"/", "/events/new"} {
+ r := get(t, h, path)
+ if r.Code != http.StatusSeeOther || !strings.HasPrefix(r.Header().Get("Location"), "/signin") {
+ t.Errorf("protected redirect changed for %s: status %d", path, r.Code)
+ }
+ }
+}