Send only the Referer's scheme and host to Sentry (closes #548)
check / check (push) Waiting to run

A Sentry event kept the Referer header verbatim, and a Referer can be
an entrypoint URL: a sender that follows the README's http:// to
https:// redirect sends the URL it was redirected from, and a browser
sends the 404 page's URL under /h/ when it fetches that page's
stylesheet. The Sentry hook now keeps only the Referer's scheme and
host. The access log's reduction moves, unchanged, into a new package,
internal/referer, as SchemeAndHost; the access log and the Sentry hook
both call it there. The comment above sentryKeepsHeader and the
README's Sentry passage say so.

Model: opus-5-5
This commit is contained in:
2026-10-15 14:54:55 +00:00
parent 872e4eb4a1
commit 8f0129d421
6 changed files with 157 additions and 35 deletions
+3 -26
View File
@@ -22,6 +22,7 @@ import (
"sneak.berlin/go/webhooker/internal/config"
"sneak.berlin/go/webhooker/internal/globals"
"sneak.berlin/go/webhooker/internal/logfield"
"sneak.berlin/go/webhooker/internal/referer"
"sneak.berlin/go/webhooker/internal/session"
)
@@ -48,10 +49,6 @@ const (
// pick the size of the line it writes.
redactedQuery = "?(redacted)"
// redactedReferer stands in for a Referer the access log cannot
// reduce to its scheme and host; see accessLogReferer.
redactedReferer = "(redacted)"
// maxLogRequestIDBytes bounds the request id, which is also
// client-supplied: chi's RequestID middleware passes an inbound
// X-Request-Id header through verbatim. Its generated form is an
@@ -342,27 +339,6 @@ func accessLogURL(r *http.Request, status int) string {
return pattern
}
// accessLogReferer returns the value for the access log's referer
// field: the Referer's scheme and host, never its path or query. The
// path can be an entrypoint URL, which carries the UUID: a sender that
// follows a redirect from http:// to https:// sends the URL it was
// redirected from, and a browser sends the 404 page's URL under /h/
// when it fetches that page's stylesheet. A Referer without both a
// scheme and a host is logged as redactedReferer.
func accessLogReferer(r *http.Request) string {
referer := r.Referer()
if referer == "" {
return ""
}
parsed, err := url.Parse(referer)
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
return redactedReferer
}
return parsed.Scheme + "://" + parsed.Host
}
// Logging returns middleware that logs each HTTP request with
// timing and metadata.
func (s *Middleware) Logging() func(http.Handler) http.Handler {
@@ -413,7 +389,8 @@ func (s *Middleware) Logging() func(http.Handler) http.Handler {
requestID, maxLogRequestIDBytes,
),
"referer", logfield.Truncate(
accessLogReferer(r), logfield.MaxBytes,
referer.SchemeAndHost(r.Referer()),
logfield.MaxBytes,
),
"proto", r.Proto,
"remoteIP", RemoteIP(r),