Skip to content

Commit 18c419d

Browse files
authored
W3C propagation internal shared tests (#43)
* extracting a zero trace ID is an error * change default propagation style to just Datadog * disallow extra traceparent fields in version zero * escape equal signs in "origin" field of W3C tracestate * comment on = -> ~ in origin
1 parent 440c28e commit 18c419d

File tree

7 files changed

+52
-13
lines changed

7 files changed

+52
-13
lines changed

src/datadog/error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ struct Error {
6969
ENVOY_HTTP_CLIENT_FAILURE = 44,
7070
MULTIPLE_PROPAGATION_STYLE_ENVIRONMENT_VARIABLES = 45,
7171
DUPLICATE_PROPAGATION_STYLE = 46,
72+
ZERO_TRACE_ID = 47,
7273
};
7374

7475
Code code;

src/datadog/tracer.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
363363
// producing a root span
364364
// - if origin is _not_ set, then it's an error
365365
// - trace ID and parent ID means we're extracting a child span
366+
// - if trace ID is zero, then that's an error.
366367

367368
if (!trace_id && !parent_id) {
368369
return Error{Error::NO_SPAN_TO_EXTRACT,
@@ -396,11 +397,16 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
396397
parent_id = 0;
397398
}
398399

399-
// We're done extracting fields. Now create the span.
400-
// This is similar to what we do in `create_span`.
401400
assert(parent_id);
402401
assert(trace_id);
403402

403+
if (*trace_id == 0) {
404+
return Error{Error::ZERO_TRACE_ID,
405+
"extracted zero value for trace ID, which is invalid"};
406+
}
407+
408+
// We're done extracting fields. Now create the span.
409+
// This is similar to what we do in `create_span`.
404410
span_data->apply_config(*defaults_, config, clock_);
405411
span_data->span_id = generator_->span_id();
406412
span_data->trace_id = *trace_id;

src/datadog/tracer_config.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ struct TracerConfig {
6363
// All styles indicated by `injection_styles` are used for injection.
6464
// `injection_styles` is overridden by the `DD_TRACE_PROPAGATION_STYLE_INJECT`
6565
// and `DD_TRACE_PROPAGATION_STYLE` environment variables.
66-
std::vector<PropagationStyle> injection_styles = {PropagationStyle::W3C,
67-
PropagationStyle::DATADOG};
66+
std::vector<PropagationStyle> injection_styles = {PropagationStyle::DATADOG};
6867

6968
// `extraction_styles` indicates with which tracing systems trace propagation
7069
// will be compatible when extracting (receiving) trace context.
@@ -74,8 +73,7 @@ struct TracerConfig {
7473
// `extraction_styles` is overridden by the
7574
// `DD_TRACE_PROPAGATION_STYLE_EXTRACT` and `DD_TRACE_PROPAGATION_STYLE`
7675
// environment variables.
77-
std::vector<PropagationStyle> extraction_styles = {PropagationStyle::W3C,
78-
PropagationStyle::DATADOG};
76+
std::vector<PropagationStyle> extraction_styles = {PropagationStyle::DATADOG};
7977

8078
// `report_hostname` indicates whether the tracer will include the result of
8179
// `gethostname` with traces sent to the collector.

src/datadog/w3c_propagation.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ Optional<std::string> extract_traceparent(ExtractedData& result,
5353
"([0-9a-f]{16})" // hex parent span ID (match group 3)
5454
"-"
5555
"([0-9a-f]{2})" // hex "trace-flags" (match group 4)
56-
"(?:$|-.*)"; // either the end, or a hyphen preceding further fields
56+
"($|-.*)"; // either the end, or a hyphen preceding further fields (match
57+
// group 5)
5758
static const std::regex regex{pattern};
5859

5960
std::match_results<StringView::iterator> match;
@@ -62,18 +63,23 @@ Optional<std::string> extract_traceparent(ExtractedData& result,
6263
}
6364

6465
assert(match.ready());
65-
assert(match.size() == 4 + 1);
66+
assert(match.size() == 5 + 1);
6667

6768
const auto to_string_view = [](const auto& submatch) {
6869
assert(submatch.first <= submatch.second);
6970
return StringView{submatch.first,
7071
std::size_t(submatch.second - submatch.first)};
7172
};
7273

73-
if (to_string_view(match[1]) == "ff") {
74+
const auto version = to_string_view(match[1]);
75+
if (version == "ff") {
7476
return "invalid_version";
7577
}
7678

79+
if (version == "00" && !to_string_view(match[5]).empty()) {
80+
return "malformed_traceparent";
81+
}
82+
7783
result.trace_id = *TraceID::parse_hex(to_string_view(match[2]));
7884
if (result.trace_id == 0) {
7985
return "trace_id_zero";
@@ -190,6 +196,11 @@ void parse_datadog_tracestate(ExtractedData& result, StringView datadog_value) {
190196
const auto value = range(kv_separator + 1, pair_end);
191197
if (key == "o") {
192198
result.origin = std::string{value};
199+
// Equal signs are allowed in the value of "origin," but equal signs are
200+
// also special characters in the `tracestate` encoding. So, equal signs
201+
// that would appear in the "origin" value are converted to tildes during
202+
// encoding. Here, in decoding, we undo the conversion.
203+
std::replace(result.origin->begin(), result.origin->end(), '~', '=');
193204
} else if (key == "s") {
194205
const auto maybe_priority = parse_int(value, 10);
195206
if (!maybe_priority) {
@@ -322,7 +333,8 @@ std::string encode_datadog_tracestate(
322333
result += ";o:";
323334
result += *origin;
324335
std::replace_if(result.end() - origin->size(), result.end(),
325-
verboten(0x20, 0x7e, ",;="), '_');
336+
verboten(0x20, 0x7e, ",;~"), '_');
337+
std::replace(result.end() - origin->size(), result.end(), '=', '~');
326338
}
327339

328340
for (const auto& [key, value] : trace_tags) {

test/test_span.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ TEST_CASE("injecting W3C tracestate header") {
628628
{{"x-datadog-trace-id", "1"}, {"x-datadog-parent-id", "1"},
629629
{"x-datadog-origin", "France, is a country=nation; so is 台北."}},
630630
// The "s:-1" comes from the 0% sample rate.
631-
"dd=s:-1;o:France_ is a country_nation_ so is ______."},
631+
"dd=s:-1;o:France_ is a country~nation_ so is ______."},
632632

633633
{__LINE__, "replace invalid characters in trace tag key",
634634
{{"x-datadog-trace-id", "1"}, {"x-datadog-parent-id", "1"},

test/test_tracer.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,18 @@ TEST_CASE("span extraction") {
369369
{"x-b3-spanid", "def"},
370370
{"x-b3-sampled", "99999999999999999999999999"}},
371371
Error::OUT_OF_RANGE_INTEGER},
372+
{__LINE__,
373+
"zero x-datadog-trace-id",
374+
{PropagationStyle::DATADOG},
375+
{{"x-datadog-trace-id", "0"},
376+
{"x-datadog-parent-id", "1234"},
377+
{"x-datadog-sampling-priority", "0"}},
378+
Error::ZERO_TRACE_ID},
379+
{__LINE__,
380+
"zero x-b3-traceid",
381+
{PropagationStyle::B3},
382+
{{"x-b3-traceid", "0"}, {"x-b3-spanid", "123"}, {"x-b3-sampled", "0"}},
383+
Error::ZERO_TRACE_ID},
372384
}));
373385

374386
CAPTURE(test_case.line);
@@ -624,6 +636,10 @@ TEST_CASE("span extraction") {
624636
{__LINE__, "invalid: parent ID zero",
625637
"00-4bf92f3577b34da6a3ce929d0e0e4736-0000000000000000-00", // traceparent
626638
"parent_id_zero"}, // expected_error_tag_value
639+
640+
{__LINE__, "invalid: trailing characters when version is zero",
641+
"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-foo", // traceparent
642+
"malformed_traceparent"}, // expected_error_tag_value
627643
}));
628644
// clang-format on
629645

@@ -807,6 +823,12 @@ TEST_CASE("span extraction") {
807823
nullopt, // expected_additional_w3c_tracestate
808824
"x:wow;y:wow"}, // expected_additional_datadog_w3c_tracestate
809825

826+
{__LINE__, "origin with escaped equal sign",
827+
traceparent_drop, // traceparent
828+
"dd=o:France~country", // tracestate
829+
0, // expected_sampling_priority
830+
"France=country"}, // expected_origin
831+
810832
{__LINE__, "traceparent and tracestate sampling agree (1/4)",
811833
traceparent_drop, // traceparent
812834
"dd=s:0", // tracestate

test/test_tracer_config.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,12 +1003,12 @@ TEST_CASE("TracerConfig propagation styles") {
10031003
TracerConfig config;
10041004
config.defaults.service = "testsvc";
10051005

1006-
SECTION("default styles are [W3C, Datadog]") {
1006+
SECTION("default style is Datadog") {
10071007
auto finalized = finalize_config(config);
10081008
REQUIRE(finalized);
10091009

10101010
const std::vector<PropagationStyle> expected_styles = {
1011-
PropagationStyle::W3C, PropagationStyle::DATADOG};
1011+
PropagationStyle::DATADOG};
10121012

10131013
REQUIRE(finalized->injection_styles == expected_styles);
10141014
REQUIRE(finalized->extraction_styles == expected_styles);

0 commit comments

Comments
 (0)