From afe4b3bb70da9538c7582ae40fc84f0924cc8d6e Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Sun, 4 Oct 2026 08:31:17 +0000 Subject: [PATCH] Send the request's ID back as X-Request-Id A middleware right after chi's RequestID sets the X-Request-Id response header from the ID RequestID stored in the request context, so every response carries it and a client can quote it when reporting a problem. README "Routes" says where the ID comes from. Model: opus-5-5 --- README.md | 6 ++++++ internal/middleware/middleware.go | 14 ++++++++++++++ internal/server/routes.go | 1 + 3 files changed, 21 insertions(+) diff --git a/README.md b/README.md index 588e2db..fece930 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,12 @@ path under `/v1/` answers 200, in maintenance mode too. authentication with `metrics.username` and `metrics.password`. Answers: 200; 401 without them; 404 when they are not set, as the route then does not exist. +Every response carries an `X-Request-ID` header holding the request's ID, which +a client can quote when reporting a problem: the request's own `X-Request-ID` +when it sent one, as a reverse proxy in front of pixa may, otherwise one pixa +makes up from its host name, a random string chosen at startup and a counter. +pixa's log line for the request carries the same ID as `request_id`. + Both `POST` routes accept only a form that pixa's own page served: the page puts a token in the form and sets a cookie to match, and a request without both is refused with 403, so another site cannot submit the form from a visitor's diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 492ba87..758f774 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -115,6 +115,20 @@ func (s *Middleware) RateLimit( }) } +// RequestIDResponseHeader returns a middleware that sends the request's ID as +// the X-Request-Id response header, so a client can quote it when reporting a +// problem. The ID is the one chi's RequestID middleware stored in the request +// context, so RequestID must run first. +func (s *Middleware) RequestIDResponseHeader() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set(middleware.RequestIDHeader, + middleware.GetReqID(r.Context())) + next.ServeHTTP(w, r) + }) + } +} + type loggingResponseWriter struct { http.ResponseWriter diff --git a/internal/server/routes.go b/internal/server/routes.go index f341e8a..f92b472 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -29,6 +29,7 @@ func (s *Server) SetupRoutes() { s.router.Use(middleware.Recoverer) s.router.Use(middleware.RequestID) + s.router.Use(s.mw.RequestIDResponseHeader()) s.router.Use(s.mw.ClientIP()) s.router.Use(s.mw.SecurityHeaders()) s.router.Use(s.mw.Logging())