package server import ( "context" "crypto/rand" "fmt" "net/http" "git.codelab.vc/pkg/httpx/internal/requestid" ) // RequestID returns a middleware that assigns a unique request ID to each // request. If the incoming request already has an X-Request-Id header, that // value is used. Otherwise a new UUID v4 is generated via crypto/rand. // // The request ID is stored in the request context (retrieve with // RequestIDFromContext) and set on the response X-Request-Id header. func RequestID() Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { id := r.Header.Get("X-Request-Id") if id == "" { id = newUUID() } ctx := requestid.NewContext(r.Context(), id) w.Header().Set("X-Request-Id", id) next.ServeHTTP(w, r.WithContext(ctx)) }) } } // RequestIDFromContext returns the request ID from the context, or an empty // string if none is set. func RequestIDFromContext(ctx context.Context) string { return requestid.FromContext(ctx) } // newUUID generates a UUID v4 string using crypto/rand. func newUUID() string { var uuid [16]byte _, _ = rand.Read(uuid[:]) // Set version 4 (bits 12-15 of time_hi_and_version). uuid[6] = (uuid[6] & 0x0f) | 0x40 // Set variant bits (10xx). uuid[8] = (uuid[8] & 0x3f) | 0x80 return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16]) }