diff --git a/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetPrintWriterTest.java b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetPrintWriterTest.java
index 796665225deb..65e47c168c29 100644
--- a/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetPrintWriterTest.java
+++ b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetPrintWriterTest.java
@@ -124,6 +124,22 @@ void testWriteWithOffset() throws IOException {
assertThat(response.getStringContent()).isEqualTo(expectedHtml);
}
+ @Test
+ void testInjectToTextHtmlWithOtherHeadStyle() throws IOException {
+ String snippet = "\n ";
+ String html = readFileAsString("beforeSnippetInjectionWithOtherHeadStyle.html");
+
+ InMemoryHttpServletResponse response = createInMemoryHttpServletResponse("text/html");
+ Servlet3SnippetInjectingResponseWrapper responseWrapper =
+ new Servlet3SnippetInjectingResponseWrapper(response, snippet);
+
+ responseWrapper.getWriter().write(html);
+ responseWrapper.getWriter().flush();
+
+ String expectedHtml = readFileAsString("afterSnippetInjectionWithOtherHeadStyle.html");
+ assertThat(response.getStringContent()).isEqualTo(expectedHtml);
+ }
+
private static InMemoryHttpServletResponse createInMemoryHttpServletResponse(String contentType) {
HttpServletResponse response = mock(HttpServletResponse.class);
when(response.getContentType()).thenReturn(contentType);
diff --git a/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetServletOutputStreamTest.java b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetServletOutputStreamTest.java
index 10ee6f14997f..d16c4c521f6c 100644
--- a/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetServletOutputStreamTest.java
+++ b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/SnippetServletOutputStreamTest.java
@@ -125,6 +125,25 @@ void testHeadTagSplitAcrossTwoWrites() throws IOException {
assertThat(out.getBytes()).isEqualTo(expectedSecondPart.getBytes(UTF_8));
}
+ @Test
+ void testInjectionWithOtherHeadStyle() throws IOException {
+ String snippet = "\n ";
+ byte[] html = readFileAsBytes("beforeSnippetInjectionWithOtherHeadStyle.html");
+
+ InjectionState obj = createInjectionStateForTesting(snippet, UTF_8);
+ InMemoryServletOutputStream out = new InMemoryServletOutputStream();
+
+ Supplier stringSupplier = snippet::toString;
+ OutputStreamSnippetInjectionHelper helper =
+ new OutputStreamSnippetInjectionHelper(stringSupplier);
+ boolean injected = helper.handleWrite(obj, out, html, 0, html.length);
+ assertThat(obj.getHeadTagBytesSeen()).isEqualTo(-1);
+ assertThat(injected).isEqualTo(true);
+
+ byte[] expectedHtml = readFileAsBytes("afterSnippetInjectionWithOtherHeadStyle.html");
+ assertThat(out.getBytes()).isEqualTo(expectedHtml);
+ }
+
private static InjectionState createInjectionStateForTesting(String snippet, Charset charset) {
HttpServletResponse response = mock(HttpServletResponse.class);
when(response.isCommitted()).thenReturn(false);
diff --git a/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/resources/afterSnippetInjectionWithOtherHeadStyle.html b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/resources/afterSnippetInjectionWithOtherHeadStyle.html
new file mode 100644
index 000000000000..4ef9cb954d5a
--- /dev/null
+++ b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/resources/afterSnippetInjectionWithOtherHeadStyle.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ Title
+
+
+
+
+
diff --git a/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/resources/beforeSnippetInjectionWithOtherHeadStyle.html b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/resources/beforeSnippetInjectionWithOtherHeadStyle.html
new file mode 100644
index 000000000000..65f97cac2408
--- /dev/null
+++ b/instrumentation/servlet/servlet-3.0/javaagent-unit-tests/src/test/resources/beforeSnippetInjectionWithOtherHeadStyle.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Title
+
+
+
+
+
diff --git a/instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/Servlet3SnippetInjectingResponseWrapper.java b/instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/Servlet3SnippetInjectingResponseWrapper.java
index 57dbb09401e7..be732a35b2ec 100644
--- a/instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/Servlet3SnippetInjectingResponseWrapper.java
+++ b/instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/Servlet3SnippetInjectingResponseWrapper.java
@@ -150,7 +150,8 @@ public boolean isContentTypeTextHtml() {
if (contentType == null) {
contentType = super.getHeader("content-type");
}
- return contentType != null && contentType.startsWith("text/html");
+ return contentType != null
+ && (contentType.startsWith("text/html") || contentType.startsWith("application/xhtml+xml"));
}
@Override
diff --git a/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetPrintWriterTest.java b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetPrintWriterTest.java
index ebe5adba05d6..efcd6a7a3285 100644
--- a/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetPrintWriterTest.java
+++ b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetPrintWriterTest.java
@@ -123,6 +123,22 @@ void testWriteWithOffset() throws IOException {
assertThat(response.getStringContent()).isEqualTo(expectedHtml);
}
+ @Test
+ void testInjectToTextHtmlWithOtherHeadStyle() throws IOException {
+ String snippet = "\n ";
+ String html = TestUtil.readFileAsString("beforeSnippetInjectionWithOtherHeadStyle.html");
+
+ InMemoryHttpServletResponse response = createInMemoryHttpServletResponse("text/html");
+ Servlet5SnippetInjectingResponseWrapper responseWrapper =
+ new Servlet5SnippetInjectingResponseWrapper(response, snippet);
+
+ responseWrapper.getWriter().write(html);
+ responseWrapper.getWriter().flush();
+
+ String expectedHtml = TestUtil.readFileAsString("afterSnippetInjectionWithOtherHeadStyle.html");
+ assertThat(response.getStringContent()).isEqualTo(expectedHtml);
+ }
+
private static InMemoryHttpServletResponse createInMemoryHttpServletResponse(String contentType) {
HttpServletResponse response = mock(HttpServletResponse.class);
when(response.getContentType()).thenReturn(contentType);
diff --git a/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetServletOutputStreamTest.java b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetServletOutputStreamTest.java
index 29a25b646a3e..aed84df63cf0 100644
--- a/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetServletOutputStreamTest.java
+++ b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/SnippetServletOutputStreamTest.java
@@ -127,6 +127,25 @@ void testHeadTagSplitAcrossTwoWrites() throws IOException {
assertThat(out.getBytes()).isEqualTo(expectedSecondPart.getBytes(UTF_8));
}
+ @Test
+ void testInjectionWithOtherHeadStyle() throws IOException {
+ String snippet = "\n ";
+ byte[] html = readFileAsBytes("beforeSnippetInjectionWithOtherHeadStyle.html");
+
+ InjectionState obj = createInjectionStateForTesting(snippet, UTF_8);
+ InMemoryServletOutputStream out = new InMemoryServletOutputStream();
+
+ Supplier stringSupplier = snippet::toString;
+ OutputStreamSnippetInjectionHelper helper =
+ new OutputStreamSnippetInjectionHelper(stringSupplier);
+ boolean injected = helper.handleWrite(obj, out, html, 0, html.length);
+ assertThat(obj.getHeadTagBytesSeen()).isEqualTo(-1);
+ assertThat(injected).isEqualTo(true);
+
+ byte[] expectedHtml = readFileAsBytes("afterSnippetInjectionWithOtherHeadStyle.html");
+ assertThat(out.getBytes()).isEqualTo(expectedHtml);
+ }
+
private static InjectionState createInjectionStateForTesting(String snippet, Charset charset) {
HttpServletResponse response = mock(HttpServletResponse.class);
when(response.isCommitted()).thenReturn(false);
diff --git a/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/resources/afterSnippetInjectionWithOtherHeadStyle.html b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/resources/afterSnippetInjectionWithOtherHeadStyle.html
new file mode 100644
index 000000000000..4ef9cb954d5a
--- /dev/null
+++ b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/resources/afterSnippetInjectionWithOtherHeadStyle.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ Title
+
+
+
+
+
diff --git a/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/resources/beforeSnippetInjectionWithOtherHeadStyle.html b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/resources/beforeSnippetInjectionWithOtherHeadStyle.html
new file mode 100644
index 000000000000..65f97cac2408
--- /dev/null
+++ b/instrumentation/servlet/servlet-5.0/javaagent-unit-tests/src/test/resources/beforeSnippetInjectionWithOtherHeadStyle.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Title
+
+
+
+
+
diff --git a/instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/Servlet5SnippetInjectingResponseWrapper.java b/instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/Servlet5SnippetInjectingResponseWrapper.java
index 5a9f02acc748..06d8b38e162e 100644
--- a/instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/Servlet5SnippetInjectingResponseWrapper.java
+++ b/instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/Servlet5SnippetInjectingResponseWrapper.java
@@ -142,7 +142,8 @@ public boolean isContentTypeTextHtml() {
if (contentType == null) {
contentType = super.getHeader("content-type");
}
- return contentType != null && contentType.startsWith("text/html");
+ return contentType != null
+ && (contentType.startsWith("text/html") || contentType.startsWith("application/xhtml+xml"));
}
@Override
diff --git a/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/InjectionState.java b/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/InjectionState.java
index 7986357696d9..bc34f72d0fd7 100644
--- a/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/InjectionState.java
+++ b/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/InjectionState.java
@@ -8,7 +8,7 @@
// this is shared by both ServletOutputStream and PrintWriter injection
public class InjectionState {
private static final int HEAD_TAG_WRITTEN_FAKE_VALUE = -1;
- private static final int HEAD_TAG_LENGTH = "".length();
+ private static final int HEAD_TAG_PREFIX_LENGTH = " HEAD_TAG_PREFIX_LENGTH && b == '>') {
setHeadTagWritten();
return true;
} else {
@@ -64,10 +64,11 @@ private boolean inHeadTag(int b) {
return true;
} else if (headTagBytesSeen == 4 && b == 'd') {
return true;
- } else if (headTagBytesSeen == 5 && b == '>') {
+ } else if (headTagBytesSeen == 5 && (b == '>' || Character.isWhitespace(b))) {
return true;
+ } else {
+ return headTagBytesSeen > 5;
}
- return false;
}
public SnippetInjectingResponseWrapper getWrapper() {