diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecorator.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecorator.java index 16a602eb4e9..df159f8f2e6 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecorator.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecorator.java @@ -58,6 +58,11 @@ public abstract class HttpClientDecorator extends UriBasedCli * not be traced to avoid self-tracing loops. */ public boolean isAgentRequest(final REQUEST request) { + // Advice runs before the instrumented method's own argument validation, so a caller + // passing a null request must not NPE here — let the real method report that itself. + if (request == null) { + return false; + } return getRequestHeader(request, DATADOG_META_LANG_HEADER_NAME) != null || getRequestHeader(request, DD_CLIENT_LIBRARY_LANGUAGE_HEADER_NAME) != null; } diff --git a/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecoratorIsAgentRequestTest.java b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecoratorIsAgentRequestTest.java new file mode 100644 index 00000000000..5d4f2c9e6ae --- /dev/null +++ b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/decorator/HttpClientDecoratorIsAgentRequestTest.java @@ -0,0 +1,57 @@ +package datadog.trace.bootstrap.instrumentation.decorator; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.net.URI; +import java.net.URISyntaxException; +import org.junit.jupiter.api.Test; + +class HttpClientDecoratorIsAgentRequestTest { + + // Regression test: advice runs before the instrumented method's own argument validation, so a + // caller passing a null request (e.g. HttpClient.sendAsync(null, ...)) must not NPE inside + // isAgentRequest -> getRequestHeader. See + // datadog.trace.instrumentation.httpclient.SendAsyncAdvice. + @Test + void isAgentRequestOfNullRequestReturnsFalseInsteadOfThrowing() { + HttpClientDecorator decorator = + new HttpClientDecorator() { + @Override + protected String[] instrumentationNames() { + return new String[] {"test"}; + } + + @Override + protected CharSequence component() { + return "test-component"; + } + + @Override + protected String method(Object request) { + return null; + } + + @Override + protected URI url(Object request) throws URISyntaxException { + return null; + } + + @Override + protected int status(Object response) { + return 0; + } + + @Override + protected String getRequestHeader(Object request, String headerName) { + throw new NullPointerException("should not be reached for a null request"); + } + + @Override + protected String getResponseHeader(Object response, String headerName) { + return null; + } + }; + + assertFalse(decorator.isAgentRequest(null)); + } +}