Skip to content

Commit aeda5a9

Browse files
mtoffl01claude
andcommitted
fix(tracer): use configurable MaxTagsHeaderLen for x-datadog-tags extraction
unmarshalPropagatingTags now uses the configured PropagatorConfig MaxTagsHeaderLen as the size cap on incoming x-datadog-tags headers instead of a hardcoded 512-byte constant. A non-positive MaxTagsHeaderLen disables extraction, mirroring the existing inject-side disable behavior. The DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH environment variable now governs both inject and extract. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent c3b9324 commit aeda5a9

2 files changed

Lines changed: 53 additions & 9 deletions

File tree

ddtrace/tracer/textmap.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,6 @@ const originHeader = "x-datadog-origin"
103103
// traceTagsHeader holds the propagated trace tags
104104
const traceTagsHeader = "x-datadog-tags"
105105

106-
// propagationExtractMaxSize limits the total size of incoming propagated tags to parse
107-
const propagationExtractMaxSize = 512
108-
109106
// PropagatorConfig defines the configuration for initializing a propagator.
110107
type PropagatorConfig struct {
111108
// BaggagePrefix specifies the prefix that will be used to store baggage
@@ -539,7 +536,7 @@ func (p *propagator) extractTextMap(reader TextMapReader) (*SpanContext, error)
539536
case originHeader:
540537
ctx.origin = v // +checklocksignore - Initialization time, freshly extracted ctx not yet shared.
541538
case traceTagsHeader:
542-
unmarshalPropagatingTags(&ctx, v)
539+
unmarshalPropagatingTags(&ctx, v, p.cfg.MaxTagsHeaderLen)
543540
default:
544541
if after, ok := strings.CutPrefix(key, p.cfg.BaggagePrefix); ok {
545542
ctx.setBaggageItem(after, v)
@@ -603,13 +600,18 @@ func overrideDatadogParentID(ctx, w3cCtx, ddCtx *SpanContext) {
603600
}
604601
}
605602

606-
// unmarshalPropagatingTags unmarshals tags from v into ctx
607-
func unmarshalPropagatingTags(ctx *SpanContext, v string) {
603+
// unmarshalPropagatingTags unmarshals tags from v into ctx, dropping the
604+
// entire header if its length exceeds maxLen. A non-positive maxLen disables
605+
// extraction (mirroring the inject side).
606+
func unmarshalPropagatingTags(ctx *SpanContext, v string, maxLen int) {
608607
if ctx.trace == nil {
609608
ctx.trace = newTrace()
610609
}
611-
if len(v) > propagationExtractMaxSize {
612-
log.Warn("Did not extract %s, size limit exceeded: %d. Incoming tags will not be propagated further.", traceTagsHeader, propagationExtractMaxSize)
610+
if maxLen <= 0 {
611+
return
612+
}
613+
if len(v) > maxLen {
614+
log.Warn("Did not extract %s, size limit exceeded: %d. Incoming tags will not be propagated further.", traceTagsHeader, maxLen)
613615
ctx.trace.setTag(keyPropagationError, "extract_max_size")
614616
return
615617
}

ddtrace/tracer/textmap_test.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,48 @@ func TestTextMapPropagator(t *testing.T) {
675675
})
676676
}
677677

678+
func TestExtractTraceTagsHeaderUsesMaxTagsHeaderLen(t *testing.T) {
679+
t.Setenv(headerPropagationStyleExtract, "datadog")
680+
const customMax = 200
681+
propagator := NewPropagator(&PropagatorConfig{
682+
MaxTagsHeaderLen: customMax,
683+
})
684+
685+
// Header is longer than the configured cap but shorter than the previous
686+
// hardcoded 512 cap, to confirm extract now honors the configured maxLen.
687+
tags := "_dd.p.k=" + strings.Repeat("a", customMax)
688+
require.Greater(t, len(tags), customMax)
689+
require.Less(t, len(tags), 512)
690+
691+
src := TextMapCarrier(map[string]string{
692+
DefaultTraceIDHeader: "1",
693+
DefaultParentIDHeader: "1",
694+
traceTagsHeader: tags,
695+
})
696+
ctx, err := propagator.Extract(src)
697+
require.NoError(t, err)
698+
assert.Equal(t, "extract_max_size", ctx.trace.tags["_dd.propagation_error"])
699+
}
700+
701+
func TestExtractTraceTagsHeaderDisabled(t *testing.T) {
702+
t.Setenv(headerPropagationStyleExtract, "datadog")
703+
propagator := NewPropagator(&PropagatorConfig{
704+
MaxTagsHeaderLen: 0, // disable, mirroring inject
705+
})
706+
707+
src := TextMapCarrier(map[string]string{
708+
DefaultTraceIDHeader: "1",
709+
DefaultParentIDHeader: "1",
710+
traceTagsHeader: "_dd.p.k=v",
711+
})
712+
ctx, err := propagator.Extract(src)
713+
require.NoError(t, err)
714+
// Disabled extract: no propagating tags, no error tag.
715+
_, hasErr := ctx.trace.tags["_dd.propagation_error"]
716+
assert.False(t, hasErr)
717+
assert.Empty(t, ctx.trace.propagatingTags)
718+
}
719+
678720
func TestEnvVars(t *testing.T) {
679721
var testEnvs []map[string]string
680722

@@ -2434,7 +2476,7 @@ func FuzzMarshalPropagatingTags(f *testing.F) {
24342476
if _, ok := sendCtx.trace.tags[keyPropagationError]; ok {
24352477
t.Skipf("Skipping invalid tags")
24362478
}
2437-
unmarshalPropagatingTags(recvCtx, marshal)
2479+
unmarshalPropagatingTags(recvCtx, marshal, pConfig.MaxTagsHeaderLen)
24382480
marshaled := sendCtx.trace.propagatingTags
24392481
unmarshaled := recvCtx.trace.propagatingTags
24402482
if !reflect.DeepEqual(sendCtx.trace.propagatingTags, recvCtx.trace.propagatingTags) {

0 commit comments

Comments
 (0)