2026-09-19 18:20:56 +03:00
|
|
|
package httpx
|
|
|
|
|
|
|
|
|
|
import (
|
2026-09-19 21:36:00 +03:00
|
|
|
"context"
|
2026-09-19 18:20:56 +03:00
|
|
|
"crypto/rand"
|
|
|
|
|
"encoding/hex"
|
2026-09-19 21:36:00 +03:00
|
|
|
"net/http"
|
2026-09-19 18:20:56 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func newRequestID() string {
|
|
|
|
|
var buf [16]byte
|
|
|
|
|
if _, err := rand.Read(buf[:]); err != nil {
|
|
|
|
|
return "0000000000000000"
|
|
|
|
|
}
|
|
|
|
|
return hex.EncodeToString(buf[:])
|
|
|
|
|
}
|
2026-09-19 21:36:00 +03:00
|
|
|
|
|
|
|
|
type requestInfoKey struct{}
|
|
|
|
|
|
|
|
|
|
// RequestInfo — данные исходного запроса, нужные сервисам (IP, User-Agent).
|
|
|
|
|
type RequestInfo struct {
|
|
|
|
|
IP string
|
|
|
|
|
UserAgent string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WithRequestInfo кладёт данные запроса в контекст (используется HTTP-слоем).
|
|
|
|
|
func WithRequestInfo(ctx context.Context, r *http.Request) context.Context {
|
|
|
|
|
return context.WithValue(ctx, requestInfoKey{}, RequestInfo{
|
|
|
|
|
IP: ClientIP(r, nil),
|
|
|
|
|
UserAgent: r.Header.Get("User-Agent"),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func requestInfo(ctx context.Context) RequestInfo {
|
|
|
|
|
if info, ok := ctx.Value(requestInfoKey{}).(RequestInfo); ok {
|
|
|
|
|
return info
|
|
|
|
|
}
|
|
|
|
|
return RequestInfo{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClientIPFromContext возвращает IP клиента для контекста huma.
|
|
|
|
|
func ClientIPFromContext(ctx context.Context) string { return requestInfo(ctx).IP }
|
|
|
|
|
|
|
|
|
|
// UserAgentFromContext возвращает User-Agent для контекста huma.
|
|
|
|
|
func UserAgentFromContext(ctx context.Context) string { return requestInfo(ctx).UserAgent }
|