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{
|
||||
Tracer: tracer,
|
||||
safeQueryParams: safeQueryParams,
|
||||
capturedRequestHeaders: capturedRequestHeaders,
|
||||
capturedResponseHeaders: capturedResponseHeaders,
|
||||
capturedRequestHeaders: canonicalizeHeaders(capturedRequestHeaders),
|
||||
capturedResponseHeaders: canonicalizeHeaders(capturedResponseHeaders),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -346,3 +346,18 @@ func defaultStatus(code int) (codes.Code, string) {
|
|||
}
|
||||
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"
|
||||
"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
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("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