Skip to content

Commit 0c79f14

Browse files
oliver-zhangMateusz Rzeszuteklaurit
authored
snippet inject support like <head lang="en"> (#8736)
Co-authored-by: Mateusz Rzeszutek <[email protected]> Co-authored-by: Lauri Tulmin <[email protected]>
1 parent f8f8794 commit 0c79f14

File tree

11 files changed

+121
-6
lines changed

11 files changed

+121
-6
lines changed

instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetPrintWriterTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@ void testWriteWithOffset() throws IOException {
124124
assertThat(response.getStringContent()).isEqualTo(expectedHtml);
125125
}
126126

127+
@Test
128+
void testInjectToTextHtmlWithOtherHeadStyle() throws IOException {
129+
String snippet = "\n <script type=\"text/javascript\"> Test </script>";
130+
String html = readFileAsString("beforeSnippetInjectionWithOtherHeadStyle.html");
131+
132+
InMemoryHttpServletResponse response = createInMemoryHttpServletResponse("text/html");
133+
Servlet3SnippetInjectingResponseWrapper responseWrapper =
134+
new Servlet3SnippetInjectingResponseWrapper(response, snippet);
135+
136+
responseWrapper.getWriter().write(html);
137+
responseWrapper.getWriter().flush();
138+
139+
String expectedHtml = readFileAsString("afterSnippetInjectionWithOtherHeadStyle.html");
140+
assertThat(response.getStringContent()).isEqualTo(expectedHtml);
141+
}
142+
127143
private static InMemoryHttpServletResponse createInMemoryHttpServletResponse(String contentType) {
128144
HttpServletResponse response = mock(HttpServletResponse.class);
129145
when(response.getContentType()).thenReturn(contentType);

instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetServletOutputStreamTest.java

+19
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,25 @@ void testHeadTagSplitAcrossTwoWrites() throws IOException {
125125
assertThat(out.getBytes()).isEqualTo(expectedSecondPart.getBytes(UTF_8));
126126
}
127127

128+
@Test
129+
void testInjectionWithOtherHeadStyle() throws IOException {
130+
String snippet = "\n <script type=\"text/javascript\"> Test </script>";
131+
byte[] html = readFileAsBytes("beforeSnippetInjectionWithOtherHeadStyle.html");
132+
133+
InjectionState obj = createInjectionStateForTesting(snippet, UTF_8);
134+
InMemoryServletOutputStream out = new InMemoryServletOutputStream();
135+
136+
Supplier<String> stringSupplier = snippet::toString;
137+
OutputStreamSnippetInjectionHelper helper =
138+
new OutputStreamSnippetInjectionHelper(stringSupplier);
139+
boolean injected = helper.handleWrite(obj, out, html, 0, html.length);
140+
assertThat(obj.getHeadTagBytesSeen()).isEqualTo(-1);
141+
assertThat(injected).isEqualTo(true);
142+
143+
byte[] expectedHtml = readFileAsBytes("afterSnippetInjectionWithOtherHeadStyle.html");
144+
assertThat(out.getBytes()).isEqualTo(expectedHtml);
145+
}
146+
128147
private static InjectionState createInjectionStateForTesting(String snippet, Charset charset) {
129148
HttpServletResponse response = mock(HttpServletResponse.class);
130149
when(response.isCommitted()).thenReturn(false);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head lang="en">
4+
<script type="text/javascript"> Test </script>
5+
<meta charset="UTF-8">
6+
<title>Title</title>
7+
</head>
8+
<body>
9+
10+
</body>
11+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head lang="en">
4+
<meta charset="UTF-8">
5+
<title>Title</title>
6+
</head>
7+
<body>
8+
9+
</body>
10+
</html>

instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/Servlet3SnippetInjectingResponseWrapper.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ public boolean isContentTypeTextHtml() {
150150
if (contentType == null) {
151151
contentType = super.getHeader("content-type");
152152
}
153-
return contentType != null && contentType.startsWith("text/html");
153+
return contentType != null
154+
&& (contentType.startsWith("text/html") || contentType.startsWith("application/xhtml+xml"));
154155
}
155156

156157
@Override

instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetPrintWriterTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,22 @@ void testWriteWithOffset() throws IOException {
123123
assertThat(response.getStringContent()).isEqualTo(expectedHtml);
124124
}
125125

126+
@Test
127+
void testInjectToTextHtmlWithOtherHeadStyle() throws IOException {
128+
String snippet = "\n <script type=\"text/javascript\"> Test </script>";
129+
String html = TestUtil.readFileAsString("beforeSnippetInjectionWithOtherHeadStyle.html");
130+
131+
InMemoryHttpServletResponse response = createInMemoryHttpServletResponse("text/html");
132+
Servlet5SnippetInjectingResponseWrapper responseWrapper =
133+
new Servlet5SnippetInjectingResponseWrapper(response, snippet);
134+
135+
responseWrapper.getWriter().write(html);
136+
responseWrapper.getWriter().flush();
137+
138+
String expectedHtml = TestUtil.readFileAsString("afterSnippetInjectionWithOtherHeadStyle.html");
139+
assertThat(response.getStringContent()).isEqualTo(expectedHtml);
140+
}
141+
126142
private static InMemoryHttpServletResponse createInMemoryHttpServletResponse(String contentType) {
127143
HttpServletResponse response = mock(HttpServletResponse.class);
128144
when(response.getContentType()).thenReturn(contentType);

instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetServletOutputStreamTest.java

+19
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,25 @@ void testHeadTagSplitAcrossTwoWrites() throws IOException {
127127
assertThat(out.getBytes()).isEqualTo(expectedSecondPart.getBytes(UTF_8));
128128
}
129129

130+
@Test
131+
void testInjectionWithOtherHeadStyle() throws IOException {
132+
String snippet = "\n <script type=\"text/javascript\"> Test </script>";
133+
byte[] html = readFileAsBytes("beforeSnippetInjectionWithOtherHeadStyle.html");
134+
135+
InjectionState obj = createInjectionStateForTesting(snippet, UTF_8);
136+
InMemoryServletOutputStream out = new InMemoryServletOutputStream();
137+
138+
Supplier<String> stringSupplier = snippet::toString;
139+
OutputStreamSnippetInjectionHelper helper =
140+
new OutputStreamSnippetInjectionHelper(stringSupplier);
141+
boolean injected = helper.handleWrite(obj, out, html, 0, html.length);
142+
assertThat(obj.getHeadTagBytesSeen()).isEqualTo(-1);
143+
assertThat(injected).isEqualTo(true);
144+
145+
byte[] expectedHtml = readFileAsBytes("afterSnippetInjectionWithOtherHeadStyle.html");
146+
assertThat(out.getBytes()).isEqualTo(expectedHtml);
147+
}
148+
130149
private static InjectionState createInjectionStateForTesting(String snippet, Charset charset) {
131150
HttpServletResponse response = mock(HttpServletResponse.class);
132151
when(response.isCommitted()).thenReturn(false);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head lang="en">
4+
<script type="text/javascript"> Test </script>
5+
<meta charset="UTF-8">
6+
<title>Title</title>
7+
</head>
8+
<body>
9+
10+
</body>
11+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head lang="en">
4+
<meta charset="UTF-8">
5+
<title>Title</title>
6+
</head>
7+
<body>
8+
9+
</body>
10+
</html>

instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/Servlet5SnippetInjectingResponseWrapper.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ public boolean isContentTypeTextHtml() {
142142
if (contentType == null) {
143143
contentType = super.getHeader("content-type");
144144
}
145-
return contentType != null && contentType.startsWith("text/html");
145+
return contentType != null
146+
&& (contentType.startsWith("text/html") || contentType.startsWith("application/xhtml+xml"));
146147
}
147148

148149
@Override

instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/InjectionState.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// this is shared by both ServletOutputStream and PrintWriter injection
99
public class InjectionState {
1010
private static final int HEAD_TAG_WRITTEN_FAKE_VALUE = -1;
11-
private static final int HEAD_TAG_LENGTH = "<head>".length();
11+
private static final int HEAD_TAG_PREFIX_LENGTH = "<head".length();
1212
private final SnippetInjectingResponseWrapper wrapper;
1313
private int headTagBytesSeen = 0;
1414

@@ -45,7 +45,7 @@ public boolean processByte(int b) {
4545
} else {
4646
headTagBytesSeen = 0;
4747
}
48-
if (headTagBytesSeen == HEAD_TAG_LENGTH) {
48+
if (headTagBytesSeen > HEAD_TAG_PREFIX_LENGTH && b == '>') {
4949
setHeadTagWritten();
5050
return true;
5151
} else {
@@ -64,10 +64,11 @@ private boolean inHeadTag(int b) {
6464
return true;
6565
} else if (headTagBytesSeen == 4 && b == 'd') {
6666
return true;
67-
} else if (headTagBytesSeen == 5 && b == '>') {
67+
} else if (headTagBytesSeen == 5 && (b == '>' || Character.isWhitespace(b))) {
6868
return true;
69+
} else {
70+
return headTagBytesSeen > 5;
6971
}
70-
return false;
7172
}
7273

7374
public SnippetInjectingResponseWrapper getWrapper() {

0 commit comments

Comments
 (0)