tenseleyflow/shithub / e5aab86

Browse files

handlers: register HEAD on /healthz (SR2 L8)

Strict health-probe tooling (Kubernetes-style HEAD-only liveness,
some monitoring services) issues HEAD requests. chi only registers
the verbs you ask for, so the GET-only registration returned 405
on HEAD. DO uptime tolerated this; not every consumer will.

r.Head registers a separate handler entry; same handler function so
behavior matches GET. Regression test added.
Authored by espadonne
SHA
e5aab865c0d4e7ddc96da6e880bfa39cd623716b
Parents
f7c0e60
Tree
fae55c6

2 changed files

StatusFile+-
M internal/web/handlers/handlers.go 4 0
M internal/web/handlers/handlers_test.go 25 0
internal/web/handlers/handlers.gomodified
@@ -203,7 +203,11 @@ func RegisterChi(r *chi.Mux, deps Deps) (*chi.Mux, middleware.PanicHandler, http
203203
 		// theme; serve under /static/css/chroma.css so the layout can
204204
 		// link it without a build step.
205205
 		r.Get("/static/css/chroma.css", chromaCSSHandler())
206
+		// HEAD honored alongside GET so strict probes (HEAD-only health
207
+		// checks, some Kubernetes-style livenessProbes) get 200 not 405
208
+		// (SR2 L8).
206209
 		r.Get("/healthz", healthz)
210
+		r.Head("/healthz", healthz)
207211
 		r.Handle("/readyz", readinessHandler(deps.ReadyCheck, deps.Logger))
208212
 		if deps.APIMounter != nil {
209213
 			deps.APIMounter(r)
internal/web/handlers/handlers_test.gomodified
@@ -89,3 +89,28 @@ func TestHandlers(t *testing.T) {
8989
 		})
9090
 	}
9191
 }
92
+
93
+// TestHealthzHEAD pins SR2 L8: HEAD /healthz must return 200, not
94
+// 405. Strict probes (some k8s livenessProbes, certain monitoring
95
+// tools) issue HEAD-only requests; chi only registers the methods
96
+// you ask for, so the GET-only registration would 405 HEAD probes.
97
+func TestHealthzHEAD(t *testing.T) {
98
+	t.Parallel()
99
+
100
+	mux := http.NewServeMux()
101
+	logger := slog.New(slog.NewTextHandler(io.Discard, nil))
102
+	if err := Register(mux, Deps{
103
+		Logger:      logger,
104
+		TemplatesFS: testTemplatesFS(t),
105
+		StaticFS:    testStaticFS(t),
106
+		LogoSVG:     `<svg xmlns="http://www.w3.org/2000/svg"><title>shithub</title></svg>`,
107
+	}); err != nil {
108
+		t.Fatalf("Register: %v", err)
109
+	}
110
+	req := httptest.NewRequest(http.MethodHead, "/healthz", nil)
111
+	rec := httptest.NewRecorder()
112
+	mux.ServeHTTP(rec, req)
113
+	if rec.Code != http.StatusOK {
114
+		t.Fatalf("HEAD /healthz: status %d, want 200", rec.Code)
115
+	}
116
+}