Fix HTTP headers not being canonicalized in tracing
This commit is contained in:
parent
0bf6442c5d
commit
90702d93ab
2 changed files with 67 additions and 2 deletions
|
|
@ -127,8 +127,8 @@ func NewTracer(tracer trace.Tracer, capturedRequestHeaders, capturedResponseHead
|
||||||
return &Tracer{
|
return &Tracer{
|
||||||
Tracer: tracer,
|
Tracer: tracer,
|
||||||
safeQueryParams: safeQueryParams,
|
safeQueryParams: safeQueryParams,
|
||||||
capturedRequestHeaders: capturedRequestHeaders,
|
capturedRequestHeaders: canonicalizeHeaders(capturedRequestHeaders),
|
||||||
capturedResponseHeaders: capturedResponseHeaders,
|
capturedResponseHeaders: canonicalizeHeaders(capturedResponseHeaders),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,3 +346,18 @@ func defaultStatus(code int) (codes.Code, string) {
|
||||||
}
|
}
|
||||||
return codes.Unset, ""
|
return codes.Unset, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canonicalizeHeaders converts a slice of header keys to their canonical form.
|
||||||
|
// It uses http.CanonicalHeaderKey to ensure that the headers are in a consistent format.
|
||||||
|
func canonicalizeHeaders(headers []string) []string {
|
||||||
|
if headers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
canonicalHeaders := make([]string, len(headers))
|
||||||
|
for i, header := range headers {
|
||||||
|
canonicalHeaders[i] = http.CanonicalHeaderKey(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
return canonicalHeaders
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/types"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp"
|
"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"go.opentelemetry.io/otel/trace/noop"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_safeFullURL(t *testing.T) {
|
func Test_safeFullURL(t *testing.T) {
|
||||||
|
|
@ -414,3 +415,52 @@ func TestTracerProvider(t *testing.T) {
|
||||||
span.TracerProvider().Tracer("github.com/traefik/traefik")
|
span.TracerProvider().Tracer("github.com/traefik/traefik")
|
||||||
span.TracerProvider().Tracer("other")
|
span.TracerProvider().Tracer("other")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNewTracer_HeadersCanonicalization tests that NewTracer properly canonicalizes headers.
|
||||||
|
func TestNewTracer_HeadersCanonicalization(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
inputHeaders []string
|
||||||
|
expectedCanonicalHeaders []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Empty headers",
|
||||||
|
inputHeaders: []string{},
|
||||||
|
expectedCanonicalHeaders: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Already canonical headers",
|
||||||
|
inputHeaders: []string{"Content-Type", "User-Agent", "Accept-Encoding"},
|
||||||
|
expectedCanonicalHeaders: []string{"Content-Type", "User-Agent", "Accept-Encoding"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Lowercase headers",
|
||||||
|
inputHeaders: []string{"content-type", "user-agent", "accept-encoding"},
|
||||||
|
expectedCanonicalHeaders: []string{"Content-Type", "User-Agent", "Accept-Encoding"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Mixed case headers",
|
||||||
|
inputHeaders: []string{"CoNtEnT-tYpE", "uSeR-aGeNt", "aCcEpT-eNcOdInG"},
|
||||||
|
expectedCanonicalHeaders: []string{"Content-Type", "User-Agent", "Accept-Encoding"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Create a mock tracer using a no-op tracer from OpenTelemetry
|
||||||
|
mockTracer := noop.NewTracerProvider().Tracer("test")
|
||||||
|
|
||||||
|
// Test capturedRequestHeaders
|
||||||
|
tracer := NewTracer(mockTracer, test.inputHeaders, nil, nil)
|
||||||
|
assert.Equal(t, test.expectedCanonicalHeaders, tracer.capturedRequestHeaders)
|
||||||
|
assert.Nil(t, tracer.capturedResponseHeaders)
|
||||||
|
|
||||||
|
// Test capturedResponseHeaders
|
||||||
|
tracer = NewTracer(mockTracer, nil, test.inputHeaders, nil)
|
||||||
|
assert.Equal(t, test.expectedCanonicalHeaders, tracer.capturedResponseHeaders)
|
||||||
|
assert.Nil(t, tracer.capturedRequestHeaders)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue