Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 02:15 UTC
logging: Parse request URIs in the `query` filter like the server does (#8255)
Jay Hemnani committed
Oct 19, 2026 at 13:13 UTC
612128e3b0f290af44649d7a7dcb1111fc3ebb33
2 files changed
+26
-1
modules/logging/filters.go
+9
-1
@@ -415,7 +415,15 @@ func (m QueryFilter) Filter(in zapcore.Field) zapcore.Field {
415
}
416
417
func (m QueryFilter) processQueryString(s string) string {
418
- u, err := url.Parse(s)
418
+ parse := url.Parse
419
+ if strings.HasPrefix(s, "/") {
420
+ // parse a request-target like the server does. Browsers and most
421
+ // clients strip a #fragment before sending, but a client that
422
+ // sends a raw '#' has it kept in the query by the server
423
+ // (url.ParseRequestURI does not split it off), so filter it too
424
+ parse = url.ParseRequestURI
425
+ }
426
+ u, err := parse(s)
427
if err != nil {
428
return s
429
}
modules/logging/filters_test.go
+17
@@ -127,6 +127,23 @@ func TestQueryFilterSingleValue(t *testing.T) {
127
}
128
}
129
130
+func TestQueryFilterHashInRequestURI(t *testing.T) {
131
+ f := QueryFilter{[]queryFilterAction{
132
+ {replaceAction, "token", "REDACTED"},
133
+ }}
134
+
135
+ // A request-target has no fragment, so '#' is part of the query.
136
+ for uri, expected := range map[string]string{
137
+ "/path?x=1#&token=secret": "/path?token=REDACTED&x=1%23",
138
+ "/path?token=secret#%zz": "/path",
139
+ } {
140
+ out := f.Filter(zapcore.Field{String: uri})
141
+ if out.String != expected {
142
+ t.Errorf("filtering %q: got %q, expected %q", uri, out.String, expected)
143
+ }
144
+ }
145
+}
146
+
147
func TestQueryFilterMultiValue(t *testing.T) {
148
f := QueryFilter{
149
Actions: []queryFilterAction{