Skip to content

Commit 4b3501d

Browse files
authored
fix: multiple server-tracing headers aren't handled (#1077)
* fix: multiple server-tracing headers aren't handled * PR feedback
1 parent d16e305 commit 4b3501d

File tree

2 files changed

+79
-33
lines changed

2 files changed

+79
-33
lines changed

splunk-otel-android/src/main/java/com/splunk/rum/RumResponseAttributesExtractor.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
class RumResponseAttributesExtractor implements AttributesExtractor<Request, Response> {
3030

31+
public static final String SERVER_TIMING_HEADER = "server-timing";
3132
private final ServerTimingHeaderParser serverTimingHeaderParser;
3233

3334
public RumResponseAttributesExtractor(ServerTimingHeaderParser serverTimingHeaderParser) {
@@ -52,11 +53,18 @@ public void onEnd(
5253
}
5354

5455
private void onResponse(AttributesBuilder attributes, Response response) {
55-
String serverTimingHeader = response.header("Server-Timing");
56-
String[] ids = serverTimingHeaderParser.parse(serverTimingHeader);
57-
if (ids.length == 2) {
58-
attributes.put(LINK_TRACE_ID_KEY, ids[0]);
59-
attributes.put(LINK_SPAN_ID_KEY, ids[1]);
60-
}
56+
response.headers()
57+
.forEach(
58+
header -> {
59+
if (!header.getFirst().equalsIgnoreCase(SERVER_TIMING_HEADER)) {
60+
return;
61+
}
62+
63+
String[] ids = serverTimingHeaderParser.parse(header.getSecond());
64+
if (ids.length == 2) {
65+
attributes.put(LINK_TRACE_ID_KEY, ids[0]);
66+
attributes.put(LINK_SPAN_ID_KEY, ids[1]);
67+
}
68+
});
6169
}
6270
}

splunk-otel-android/src/test/java/com/splunk/rum/RumResponseAttributesExtractorTest.java

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,64 @@ class RumResponseAttributesExtractorTest {
3636

3737
@Test
3838
void spanDecoration() {
39-
ServerTimingHeaderParser headerParser = mock(ServerTimingHeaderParser.class);
40-
when(headerParser.parse("headerValue"))
41-
.thenReturn(new String[] {"9499195c502eb217c448a68bfe0f967c", "fe16eca542cd5d86"});
39+
Request fakeRequest = mock(Request.class);
40+
Response response =
41+
getBaseRuestBuilder(fakeRequest)
42+
.addHeader(
43+
"Server-Timing",
44+
"traceparent;desc=\"00-00000000000000000000000000000001-0000000000000001-01\"")
45+
.build();
46+
Attributes attributes = performAttributesExtraction(fakeRequest, response);
47+
48+
assertThat(attributes)
49+
.containsOnly(
50+
entry(COMPONENT_KEY, "http"),
51+
entry(LINK_TRACE_ID_KEY, "00000000000000000000000000000001"),
52+
entry(LINK_SPAN_ID_KEY, "0000000000000001"));
53+
}
4254

55+
@Test
56+
void ignoresMalformed() {
4357
Request fakeRequest = mock(Request.class);
4458
Response response =
45-
new Response.Builder()
46-
.request(fakeRequest)
47-
.protocol(Protocol.HTTP_1_1)
48-
.message("hello")
49-
.code(200)
50-
.addHeader("Server-Timing", "headerValue")
59+
getBaseRuestBuilder(fakeRequest)
60+
.addHeader("Server-Timing", "othervalue 1")
61+
.addHeader(
62+
"Server-Timing",
63+
"traceparent;desc=\"00-00000000000000000000000000000001-0000000000000001-01\"")
64+
.addHeader("Server-Timing", "othervalue 2")
5165
.build();
66+
Attributes attributes = performAttributesExtraction(fakeRequest, response);
5267

53-
RumResponseAttributesExtractor attributesExtractor =
54-
new RumResponseAttributesExtractor(headerParser);
55-
AttributesBuilder attributesBuilder = Attributes.builder();
56-
attributesExtractor.onStart(attributesBuilder, Context.root(), fakeRequest);
57-
attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeRequest, response, null);
58-
Attributes attributes = attributesBuilder.build();
68+
assertThat(attributes)
69+
.containsOnly(
70+
entry(COMPONENT_KEY, "http"),
71+
entry(LINK_TRACE_ID_KEY, "00000000000000000000000000000001"),
72+
entry(LINK_SPAN_ID_KEY, "0000000000000001"));
73+
}
74+
75+
@Test
76+
void lastMatchingWins() {
77+
Request fakeRequest = mock(Request.class);
78+
Response response =
79+
getBaseRuestBuilder(fakeRequest)
80+
.addHeader(
81+
"Server-Timing",
82+
"traceparent;desc=\"00-00000000000000000000000000000001-0000000000000001-01\"")
83+
.addHeader(
84+
"Server-Timing",
85+
"traceparent;desc=\"00-00000000000000000000000000000002-0000000000000002-01\"")
86+
.addHeader(
87+
"Server-Timing",
88+
"traceparent;desc=\"00-00000000000000000000000000000003-0000000000000003-01\"")
89+
.build();
90+
Attributes attributes = performAttributesExtraction(fakeRequest, response);
5991

6092
assertThat(attributes)
6193
.containsOnly(
6294
entry(COMPONENT_KEY, "http"),
63-
entry(LINK_TRACE_ID_KEY, "9499195c502eb217c448a68bfe0f967c"),
64-
entry(LINK_SPAN_ID_KEY, "fe16eca542cd5d86"));
95+
entry(LINK_TRACE_ID_KEY, "00000000000000000000000000000003"),
96+
entry(LINK_SPAN_ID_KEY, "0000000000000003"));
6597
}
6698

6799
@Test
@@ -70,21 +102,27 @@ void spanDecoration_noLinkingHeader() {
70102
when(headerParser.parse(null)).thenReturn(new String[0]);
71103

72104
Request fakeRequest = mock(Request.class);
73-
Response response =
74-
new Response.Builder()
75-
.request(fakeRequest)
76-
.protocol(Protocol.HTTP_1_1)
77-
.message("hello")
78-
.code(200)
79-
.build();
105+
Response response = getBaseRuestBuilder(fakeRequest).build();
106+
Attributes attributes = performAttributesExtraction(fakeRequest, response);
107+
108+
assertThat(attributes).containsOnly(entry(COMPONENT_KEY, "http"));
109+
}
80110

111+
private static Attributes performAttributesExtraction(Request fakeRequest, Response response) {
81112
RumResponseAttributesExtractor attributesExtractor =
82-
new RumResponseAttributesExtractor(headerParser);
113+
new RumResponseAttributesExtractor(new ServerTimingHeaderParser());
83114
AttributesBuilder attributesBuilder = Attributes.builder();
84-
attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeRequest, response, null);
85115
attributesExtractor.onStart(attributesBuilder, Context.root(), fakeRequest);
116+
attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeRequest, response, null);
86117
Attributes attributes = attributesBuilder.build();
118+
return attributes;
119+
}
87120

88-
assertThat(attributes).containsOnly(entry(COMPONENT_KEY, "http"));
121+
private Response.Builder getBaseRuestBuilder(Request fakeRequest) {
122+
return new Response.Builder()
123+
.request(fakeRequest)
124+
.protocol(Protocol.HTTP_1_1)
125+
.message("hello")
126+
.code(200);
89127
}
90128
}

0 commit comments

Comments
 (0)