pixa's own RequestID middleware replaces chi's and the response-header middleware. It keeps a request's own X-Request-Id only when it is at most 64 letters, digits, '-', '_' or '.', so an over-long or odd value is never sent back or upstream, and otherwise makes a random ID with crypto/rand, which tells nothing about the host or how many requests pixa served. It stores the ID under chi's RequestIDKey, where the logging middleware, the handlers and the fetcher read it. Model: opus-5-5
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// TestFetchSendsRequestID verifies that a fetch sends the ID of the request
|
||||
// it serves, which chi's RequestID middleware stores in the request context,
|
||||
// it serves, which the RequestID middleware stores in the request context,
|
||||
// to the upstream host as X-Request-Id, so the fetch can be found in that
|
||||
// host's logs.
|
||||
func TestFetchSendsRequestID(t *testing.T) {
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
basicauth "github.com/99designs/basicauth-go"
|
||||
@@ -115,16 +118,28 @@ func (s *Middleware) RateLimit(
|
||||
})
|
||||
}
|
||||
|
||||
// RequestIDResponseHeader returns a middleware that sends the request's ID as
|
||||
// requestIDPattern is what a request's own X-Request-Id must look like to be
|
||||
// kept as its ID: 1 to 64 letters, digits, '-', '_' or '.'.
|
||||
var requestIDPattern = regexp.MustCompile(`^[A-Za-z0-9._-]{1,64}$`)
|
||||
|
||||
// RequestID returns a middleware that gives each request an ID and sends it 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 {
|
||||
// problem. The ID is the request's own X-Request-Id when that matches
|
||||
// requestIDPattern, and otherwise a random one, which tells nothing about the
|
||||
// machine or the traffic. It is stored in the request context under chi's
|
||||
// RequestIDKey, where the logging middleware, the handlers and the upstream
|
||||
// fetch read it.
|
||||
func (s *Middleware) RequestID() 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)
|
||||
id := r.Header.Get(middleware.RequestIDHeader)
|
||||
if !requestIDPattern.MatchString(id) {
|
||||
id = rand.Text()
|
||||
}
|
||||
|
||||
w.Header().Set(middleware.RequestIDHeader, id)
|
||||
ctx := context.WithValue(r.Context(), middleware.RequestIDKey, id)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@ func (s *Server) SetupRoutes() {
|
||||
s.router = chi.NewRouter()
|
||||
|
||||
s.router.Use(middleware.Recoverer)
|
||||
s.router.Use(middleware.RequestID)
|
||||
s.router.Use(s.mw.RequestIDResponseHeader())
|
||||
s.router.Use(s.mw.RequestID())
|
||||
s.router.Use(s.mw.ClientIP())
|
||||
s.router.Use(s.mw.SecurityHeaders())
|
||||
s.router.Use(s.mw.Logging())
|
||||
|
||||
Reference in New Issue
Block a user