Repository navigation
Conversation
Pull request dashboard statusWaiting on the author · refreshed 2026-11-02 06:58 UTC Move out of draft to request review. Status above doesn't look right?
|
Co-authored-by: trask <218610+trask@users.noreply.github.com>
Co-authored-by: trask <218610+trask@users.noreply.github.com>
| resetAsyncResponse(req, resp, true); | ||
| return; | ||
| } else if ("stream-forward".equals(snippetScenario)) { | ||
| resp.setHeader("X-Snippet-Scenario", snippetScenario); |
| resp.setContentType("text/html"); | ||
| resp.getOutputStream().write("<head>".getBytes(UTF_8)); | ||
| } else if ("async-reset".equals(snippetScenario)) { | ||
| resp.setHeader("X-Snippet-Scenario", snippetScenario); |
| asyncContext.dispatch("/test.jsp"); | ||
| return; | ||
| } else if ("error-dispatch".equals(snippetScenario)) { | ||
| resp.setHeader("X-Snippet-Scenario", snippetScenario); |
There was a problem hiding this comment.
🟡 Changes recommended
A cached response writer reused after a forward can leave writer ownership cleared, allowing both output paths to advance the shared matcher and miss snippet injection at <head>.
1 open issue
What changed in this PR
This PR restores shared snippet-injection state across Servlet 3 and Servlet 5 response-body reuse, building on #21104’s protection against recycled streams carrying stale state into later requests.
Changes:
- Share matching, injection, and Content-Length state across wrappers while coordinating writer and stream output.
- Handle body replacement through resets, forwards, and error dispatches, including cached-writer refresh.
- Expand lifecycle regression coverage and deploy freshly built servlet WARs into Jetty 10/11 smoke tests.
| File | Description |
|---|---|
smoke-tests/src/test/java/io/opentelemetry/smoketest/appserver/JettySmokeTest.java |
Adds lifecycle scenarios and current-WAR deployment. |
smoke-tests/images/servlet/servlet-5.0/src/main/webapp/WEB-INF/web.xml |
Enables async processing and maps error dispatch. |
smoke-tests/images/servlet/servlet-5.0/src/main/java/io/opentelemetry/smoketest/matrix/SnippetErrorServlet.java |
Provides the replacement error-page body. |
smoke-tests/images/servlet/servlet-5.0/src/main/java/io/opentelemetry/smoketest/matrix/SnippetErrorException.java |
Supplies a dedicated error-dispatch trigger. |
smoke-tests/images/servlet/servlet-5.0/src/main/java/io/opentelemetry/smoketest/matrix/JspServlet.java |
Adds forward, reset, and error fixtures. |
smoke-tests/images/servlet/servlet-3.0/src/main/webapp/WEB-INF/web.xml |
Enables async processing and maps error dispatch. |
smoke-tests/images/servlet/servlet-3.0/src/main/java/io/opentelemetry/smoketest/matrix/SnippetErrorServlet.java |
Provides the replacement error-page body. |
smoke-tests/images/servlet/servlet-3.0/src/main/java/io/opentelemetry/smoketest/matrix/SnippetErrorException.java |
Supplies a dedicated error-dispatch trigger. |
smoke-tests/images/servlet/servlet-3.0/src/main/java/io/opentelemetry/smoketest/matrix/JspServlet.java |
Adds forward, reset, and error fixtures. |
smoke-tests/build.gradle.kts |
Packages current servlet WARs as test resources. |
instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/snippet/SnippetInjectingPrintWriter.java |
Accepts shared state and marks writer ownership. |
instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/snippet/OutputStreamSnippetInjectionHelper.java |
Checks writer ownership before stream matching. |
instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/service/ServletResponseResetInstrumentation.java |
Matches response reset methods. |
instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/service/RequestDispatcherForwardInstrumentation.java |
Matches dispatcher forward methods. |
instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/SnippetInjectingResponseWrapper.java |
Adds Content-Length rollback support. |
instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/InjectionState.java |
Centralizes shared body and lifecycle state. |
instrumentation/servlet/servlet-5.0/testing/src/main/java/io/opentelemetry/instrumentation/servlet/v5_0/TestServlet5.java |
Adds dispatch and output-ownership fixtures. |
instrumentation/servlet/servlet-5.0/jetty11-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/jetty/dispatch/JettyServlet5ForwardTest.java |
Tests replacement bodies and rejected operations. |
instrumentation/servlet/servlet-5.0/javaagent/src/unitTests/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/InjectionStateLifetimeTest.java |
Expands shared-state and cached-writer coverage. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/ServletOutputStreamInjectionState.java |
Attaches the shared body state to streams. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/snippet/Servlet5SnippetInjectingResponseWrapper.java |
Reuses body state and refreshes cached writers. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/Servlet5ResponseResetAdvice.java |
Updates state after successful native resets. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/Servlet5ResponseInjectionState.java |
Associates responses with request-valid state. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/Servlet5RequestDispatcherForwardAdvice.java |
Tracks forward entry and completion. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/service/JakartaServletServiceAdvice.java |
Applies pending forward resets at service entry. |
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/JakartaServletInstrumentationModule.java |
Registers reset and forward instrumentation. |
instrumentation/servlet/servlet-3.0/testing/src/main/java/io/opentelemetry/instrumentation/servlet/v3_0/TestServlet3.java |
Adds dispatch and output-ownership fixtures. |
instrumentation/servlet/servlet-3.0/testing/src/main/java/io/opentelemetry/instrumentation/servlet/v3_0/jetty/BaseJettyDispatchTest.java |
Tests replacement bodies and rejected operations. |
instrumentation/servlet/servlet-3.0/javaagent/src/unitTests/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/InjectionStateLifetimeTest.java |
Expands shared-state and cached-writer coverage. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/ServletOutputStreamInjectionState.java |
Attaches the shared body state to streams. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/snippet/Servlet3SnippetInjectingResponseWrapper.java |
Reuses body state and refreshes cached writers. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3ResponseResetAdvice.java |
Updates state after successful native resets. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3ResponseInjectionState.java |
Associates responses with request-valid state. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3RequestDispatcherForwardAdvice.java |
Tracks forward entry and completion. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3InstrumentationModule.java |
Registers reset and forward instrumentation. |
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3Advice.java |
Applies pending forward resets at service entry. |
Review effort: Balanced
Co-authored-by: trask <218610+trask@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
Regression evidence covers Jetty 10/11, but the shared-state reset/forward/error lifecycle changes require maintainer validation of body-discard and writer-ownership behavior on other supported servlet containers.
No open issues 🎉
1 resolved since last review
Review effort: Balanced

Share servlet snippet matching and Content-Length state across wrappers that retain the same response body, including includes and async redispatch. Stacked on #21104.
Restart injection when a reset, forward, or error dispatch replaces the body. Preserve native writer/stream ownership and roll back Content-Length only after the old body is discarded.
Container-specific body-discard and writer-ownership behavior outside Jetty 10/11 still needs maintainer review.