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 834ab82e41c..33204b14028 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 @@ -95,14 +95,21 @@ public AgentSpan onRequest(final AgentSpan span, final REQUEST request) { ssrfIastCheck(request); + System.out.println("hi im here"); if (CLIENT_TAG_HEADERS) { + System.out.println("now im here"); for (Map.Entry headerTag : traceConfig(span).getRequestHeaderTags().entrySet()) { + System.out.println("now im inside"); String headerValue = getRequestHeader(request, headerTag.getKey()); if (null != headerValue) { + System.out.println("now im inside inside"); + System.out.println("headerTag: " + headerTag.getValue()); + System.out.println("headerValue: " + headerValue); span.setTag(headerTag.getValue(), headerValue); } } + System.out.println("now im outside"); } } return span; diff --git a/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientDecorator.java b/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientDecorator.java index 5f9e44fd6df..1f6817b4c7d 100644 --- a/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientDecorator.java +++ b/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientDecorator.java @@ -4,6 +4,7 @@ import datadog.trace.bootstrap.instrumentation.decorator.HttpClientDecorator; import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; @@ -53,12 +54,34 @@ protected int status(final HttpContext context) { return 0; } + // RUN ./gradlew :dd-java-agent:instrumentation:apache-httpasyncclient-4:test --tests + // "ApacheHttpAsyncClientV0Test" @Override protected String getRequestHeader(HttpUriRequest request, String headerName) { + System.out.println("HEADERNAME: " + headerName); + System.out.println( + "ALL REQUEST HEADERS: " + + Arrays.toString(request.getAllHeaders())); // not printing first request header + System.out.println( + "SPECIFIC REQUEST HEADERS: " + Arrays.toString(request.getHeaders(headerName))); + System.out.println("FIRST REQUEST HEADER: " + request.getFirstHeader(headerName)); + Header header = request.getFirstHeader(headerName); if (header != null) { + System.out.println("RETURNING " + header.getValue()); return header.getValue(); + + // Header[] headers = request.getHeaders(headerName); + // List values = new ArrayList<>(); + // if (headers.length > 0) { + // for (Header header : headers) { + // values.add(header.getValue()); + // } + // System.out.println("RETURNING " + values); + // return String.join(", ", values); + } + System.out.println("RETURNING NULL"); return null; } @@ -69,6 +92,15 @@ protected String getResponseHeader(HttpContext context, String headerName) { Header header = ((HttpResponse) responseObject).getFirstHeader(headerName); if (header != null) { return header.getValue(); + + // Header[] headers = ((HttpResponse) responseObject).getHeaders(headerName); + // List values = new ArrayList<>(); + // if (headers.length > 0) { + // for (Header header : headers) { + // values.add(header.getValue()); + // } + // return String.join(", ", values); + } } return null; diff --git a/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientDecorator.java b/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientDecorator.java index 91cee1f3f85..0077a788a43 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientDecorator.java +++ b/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientDecorator.java @@ -3,6 +3,8 @@ import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.HttpClientDecorator; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpUriRequest; @@ -46,18 +48,26 @@ protected int status(final HttpResponse httpResponse) { @Override protected String getRequestHeader(HttpUriRequest request, String headerName) { - Header header = request.getFirstHeader(headerName); - if (null != header) { - return header.getValue(); + Header[] headers = request.getHeaders(headerName); + List values = new ArrayList<>(); + if (null != headers) { + for (Header header : headers) { + values.add(header.getValue()); + } + return String.join(", ", values); } return null; } @Override protected String getResponseHeader(HttpResponse response, String headerName) { - Header header = response.getFirstHeader(headerName); - if (null != header) { - return header.getValue(); + Header[] headers = response.getHeaders(headerName); + List values = new ArrayList<>(); + if (headers.length > 0) { + for (Header header : headers) { + values.add(header.getValue()); + } + return String.join(", ", values); } return null; } diff --git a/dd-java-agent/instrumentation/apache-httpclient-5/src/main/java/datadog/trace/instrumentation/apachehttpclient5/ApacheHttpClientDecorator.java b/dd-java-agent/instrumentation/apache-httpclient-5/src/main/java/datadog/trace/instrumentation/apachehttpclient5/ApacheHttpClientDecorator.java index b1988a51de6..3df098deecf 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-5/src/main/java/datadog/trace/instrumentation/apachehttpclient5/ApacheHttpClientDecorator.java +++ b/dd-java-agent/instrumentation/apache-httpclient-5/src/main/java/datadog/trace/instrumentation/apachehttpclient5/ApacheHttpClientDecorator.java @@ -4,6 +4,9 @@ import datadog.trace.bootstrap.instrumentation.decorator.HttpClientDecorator; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; @@ -49,19 +52,37 @@ protected int status(final HttpResponse httpResponse) { @Override protected String getRequestHeader(HttpRequest request, String headerName) { - Header header = request.getFirstHeader(headerName); - if (null != header) { - return header.getValue(); + System.out.println("HEADERNAME: " + headerName); + System.out.println( + "SPECIFIC REQUEST HEADERS: " + Arrays.toString(request.getHeaders(headerName))); + Header[] headers = request.getHeaders(headerName); + List values = new ArrayList<>(); + if (null != headers) { + for (Header header : headers) { + values.add(header.getValue()); + } + System.out.println("RETURNING " + String.join(",", values)); + return String.join(",", values); } + System.out.println("RETURNING NULL"); return null; } @Override protected String getResponseHeader(HttpResponse response, String headerName) { - Header header = response.getFirstHeader(headerName); - if (null != header) { - return header.getValue(); + System.out.println("HEADERNAME: " + headerName); + System.out.println( + "SPECIFIC RESPONSE HEADERS: " + Arrays.toString(response.getHeaders(headerName))); + Header[] headers = response.getHeaders(headerName); + List values = new ArrayList<>(); + if (headers.length > 0) { + for (Header header : headers) { + values.add(header.getValue()); + } + System.out.println("RETURNING " + String.join(",", values)); + return String.join(",", values); } + System.out.println("RETURNING NULL"); return null; } } diff --git a/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpAsyncClient5Test.groovy b/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpAsyncClient5Test.groovy index 162be3c5467..10f8b619e67 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpAsyncClient5Test.groovy +++ b/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpAsyncClient5Test.groovy @@ -5,6 +5,7 @@ import org.apache.hc.client5.http.async.methods.SimpleHttpRequests import org.apache.hc.client5.http.config.RequestConfig import org.apache.hc.client5.http.impl.async.HttpAsyncClients import org.apache.hc.core5.http.HttpRequest +import org.apache.hc.core5.http.message.BasicHeader import spock.lang.AutoCleanup import spock.lang.Shared @@ -55,6 +56,21 @@ abstract class ApacheHttpAsyncClient5Test extends HttpCli callback?.call() return response.code } + + @Override + int doRequest(String method, URI uri, String[] headers, String body, Closure callback) { + def request = SimpleHttpRequests.create(method, uri) + request.setConfig(RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS).build()) + for (String header : headers) { + String[] keyVal = header.split(":") + request.addHeader(new BasicHeader(keyVal[0], keyVal[1])) + } + + def future = client.execute(request, null) + def response = future.get(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS) + callback?.call() + return response.code + } } class ApacheHttpAsyncClient5NamingV0ForkedTest extends ApacheHttpAsyncClient5Test implements TestingGenericHttpNamingConventions.ClientV0 { diff --git a/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientResponseHandlerTest.groovy b/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientResponseHandlerTest.groovy index cee1a8e9770..90b9dae660d 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientResponseHandlerTest.groovy +++ b/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientResponseHandlerTest.groovy @@ -53,6 +53,23 @@ class ApacheHttpClientResponseHandlerTest extends HttpClientTest implements Test return status } + @Override + int doRequest(String method, URI uri, String[] headers, String body, Closure callback) { + def request = new BasicClassicHttpRequest(method, uri) + for (String header : headers) { + String[] keyVal = header.split(":") + request.addHeader(new BasicHeader(keyVal[0], keyVal[1])) + } + + CloseableHttpResponse response = null + def status = client.execute(request, handler) + + // handler execution is included within the client span, so we can't call the callback there. + callback?.call() + + return status + } + @Override CharSequence component() { return ApacheHttpClientDecorator.DECORATE.component() diff --git a/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientTest.groovy b/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientTest.groovy index 18438e9e4df..4cbd8d1a3b9 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientTest.groovy +++ b/dd-java-agent/instrumentation/apache-httpclient-5/src/test/groovy/ApacheHttpClientTest.groovy @@ -48,6 +48,25 @@ abstract class ApacheHttpClientTest extends HttpClientTes } } + @Override + int doRequest(String method, URI uri, String[] headers, String body, Closure callback) { + def request = createRequest(method, uri) + for (String header : headers) { + String[] keyVal = header.split(":") + request.addHeader(new BasicHeader(keyVal[0], keyVal[1])) + } + + CloseableHttpResponse response = null + try { + response = executeRequest(request, uri) + callback?.call() + return response.code + } + finally { + response?.close() + } + } + abstract T createRequest(String method, URI uri) abstract CloseableHttpResponse executeRequest(T request, URI uri) diff --git a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java index 94227b68124..c9a98441118 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java @@ -450,12 +450,20 @@ public void set(SdkHttpRequest.Builder carrier, String key, String value) { @Override protected String getRequestHeader(SdkHttpRequest request, String headerName) { - return request.firstMatchingHeader(headerName).orElse(null); + List headers = request.headers().get(headerName); + if (!headers.isEmpty()) { + return String.join(", ", headers); + } + return null; } @Override protected String getResponseHeader(SdkHttpResponse response, String headerName) { - return response.firstMatchingHeader(headerName).orElse(null); + List headers = response.headers().get(headerName); + if (!headers.isEmpty()) { + return String.join(", ", headers); + } + return null; } private void awsPojoToTags(AgentSpan span, String tagsPrefix, Object pojo) { diff --git a/dd-java-agent/instrumentation/grizzly-client-1.9/src/main/java/datadog/trace/instrumentation/grizzly/client/ClientDecorator.java b/dd-java-agent/instrumentation/grizzly-client-1.9/src/main/java/datadog/trace/instrumentation/grizzly/client/ClientDecorator.java index d9ac7a19fb6..a75223a8796 100644 --- a/dd-java-agent/instrumentation/grizzly-client-1.9/src/main/java/datadog/trace/instrumentation/grizzly/client/ClientDecorator.java +++ b/dd-java-agent/instrumentation/grizzly-client-1.9/src/main/java/datadog/trace/instrumentation/grizzly/client/ClientDecorator.java @@ -42,7 +42,7 @@ protected int status(final Response response) { @Override protected String getRequestHeader(Request request, String headerName) { - return request.getHeaders().getFirstValue(headerName); + return request.getHeaders().getJoinedValue(headerName, ", "); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Decorator.java b/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Decorator.java index f8adab0c5ee..a7b7e4b14a9 100644 --- a/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Decorator.java +++ b/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Decorator.java @@ -5,6 +5,8 @@ import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.HttpClientDecorator; import java.net.URI; +import java.util.ArrayList; +import java.util.List; public class JaxRsClientV1Decorator extends HttpClientDecorator { @@ -41,15 +43,23 @@ protected int status(final ClientResponse clientResponse) { @Override protected String getRequestHeader(ClientRequest request, String headerName) { - Object headerValue = request.getHeaders().getFirst(headerName); - if (null != headerValue) { - return headerValue.toString(); + List headers = request.getHeaders().get(headerName); + if (!headers.isEmpty()) { + List result = new ArrayList<>(); + for (Object header : headers) { + result.add(header.toString()); + } + return String.join(", ", result); } return null; } @Override protected String getResponseHeader(ClientResponse response, String headerName) { - return response.getHeaders().getFirst(headerName); + List headers = response.getHeaders().get(headerName); + if (!headers.isEmpty()) { + return String.join(", ", headers); + } + return null; } } diff --git a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/SpringWebfluxHttpClientDecorator.java b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/SpringWebfluxHttpClientDecorator.java index dd91de0d112..f596ce289e6 100644 --- a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/SpringWebfluxHttpClientDecorator.java +++ b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/SpringWebfluxHttpClientDecorator.java @@ -53,11 +53,19 @@ protected int status(final ClientResponse httpResponse) { @Override protected String getRequestHeader(ClientRequest request, String headerName) { - return request.headers().getFirst(headerName); + System.out.println("REQUEST HEADERS: " + request.headers().getValuesAsList(headerName)); + String result = String.join(",", request.headers().getValuesAsList(headerName)); + System.out.println("RESULT: " + result); + return result; } @Override protected String getResponseHeader(ClientResponse response, String headerName) { - return response.headers().asHttpHeaders().getFirst(headerName); + System.out.println( + "RESPONSE HEADERS: " + response.headers().asHttpHeaders().getValuesAsList(headerName)); + String result = + String.join(",", response.headers().asHttpHeaders().getValuesAsList(headerName)); + System.out.println("RESULT: " + result); + return result; } } diff --git a/dd-java-agent/instrumentation/synapse-3/src/main/java/datadog/trace/instrumentation/synapse3/SynapseClientDecorator.java b/dd-java-agent/instrumentation/synapse-3/src/main/java/datadog/trace/instrumentation/synapse3/SynapseClientDecorator.java index 98d330bdc39..2eebb1f94bf 100644 --- a/dd-java-agent/instrumentation/synapse-3/src/main/java/datadog/trace/instrumentation/synapse3/SynapseClientDecorator.java +++ b/dd-java-agent/instrumentation/synapse-3/src/main/java/datadog/trace/instrumentation/synapse3/SynapseClientDecorator.java @@ -5,6 +5,8 @@ import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.HttpClientDecorator; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import org.apache.http.Header; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -47,18 +49,26 @@ protected int status(final HttpResponse response) { @Override protected String getRequestHeader(HttpRequest request, String headerName) { - Header header = request.getFirstHeader(headerName); - if (null != header) { - return header.getValue(); + Header[] headers = request.getHeaders(headerName); + List values = new ArrayList<>(); + if (headers.length > 0) { + for (Header header : headers) { + values.add(header.getValue()); + } + return String.join(", ", values); } return null; } @Override protected String getResponseHeader(HttpResponse response, String headerName) { - Header header = response.getFirstHeader(headerName); - if (null != header) { - return header.getValue(); + Header[] headers = response.getHeaders(headerName); + List values = new ArrayList<>(); + if (headers.length > 0) { + for (Header header : headers) { + values.add(header.getValue()); + } + return String.join(", ", values); } return null; } diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpClientTest.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpClientTest.groovy index 228db2cd8e3..35f501f74f6 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpClientTest.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpClientTest.groovy @@ -144,6 +144,8 @@ abstract class HttpClientTest extends VersionedNamingTestBase { */ abstract int doRequest(String method, URI uri, Map headers = [:], String body = "", Closure callback = null) + abstract int doRequest(String method, URI uri, String[] headers, String body = "", Closure callback = null) + String keyStorePath() { server.keystorePath } @@ -765,7 +767,9 @@ abstract class HttpClientTest extends VersionedNamingTestBase { def "test request header #header tag mapping"() { when: def url = server.address.resolve("/success") - def status = doRequest(method, url, [(header): value]) + System.out.println("RUNNING HEADER, VALUE: " + header + ", " + value) + String[] headerVals = [header + ":" + value , header + ":" + value2] + def status = (value2 == null) ? doRequest(method, url, [(header): value]) : doRequest(method, url, headerVals) if (isDataStreamsEnabled()) { TEST_DATA_STREAMS_WRITER.waitForGroups(1) } @@ -788,11 +792,13 @@ abstract class HttpClientTest extends VersionedNamingTestBase { } where: - method | header | value | tags - 'GET' | 'X-Datadog-Test-Both-Header' | 'foo' | [ 'both_header_tag': 'foo' ] - 'GET' | 'X-Datadog-Test-Request-Header' | 'bar' | [ 'request_header_tag': 'bar' ] - 'GET' | 'X-Datadog-Test-Both-Header' | 'bar,baz' | [ 'both_header_tag': 'bar,baz' ] - 'GET' | 'X-Datadog-Test-Request-Header' | 'foo,bar' | [ 'request_header_tag': 'foo,bar' ] + method | header | value | value2 | tags + 'GET' | 'X-Datadog-Test-Both-Header' | 'foo' | null | [ 'both_header_tag': 'foo' ] + 'GET' | 'X-Datadog-Test-Request-Header' | 'bar' | null | [ 'request_header_tag': 'bar' ] + 'GET' | 'X-Datadog-Test-Both-Header' | 'bar,baz' | null | [ 'both_header_tag': 'bar,baz' ] + 'GET' | 'X-Datadog-Test-Request-Header' | 'foo,bar' | null | [ 'request_header_tag': 'foo,bar' ] + 'GET' | 'X-Datadog-Test-Both-Header' | 'bar,baz' | 'foo' | [ 'both_header_tag': 'bar,baz,foo' ] + 'GET' | 'X-Datadog-Test-Request-Header' | 'foo,bar' | 'baz' | [ 'request_header_tag': 'foo,bar,baz' ] } def "test response header #header tag mapping"() {