diff --git a/src/main/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupport.java b/src/main/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupport.java index 2c2c719..fd3b4f7 100644 --- a/src/main/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupport.java +++ b/src/main/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupport.java @@ -1,6 +1,8 @@ package com.blazemeter.jmeter.http2.core; +import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.protocol.http.util.HTTPConstants; +import org.apache.jmeter.util.JMeterUtils; import org.eclipse.jetty.client.Request; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; @@ -16,6 +18,11 @@ final class JmeterRequestHeadersSupport { static final String ATTR_USE_KEEPALIVE = "bzm.useKeepAlive"; + static final String DEFAULT_USER_AGENT_PROPERTY = + "httpclient4.default_user_agent_disabled"; + + private static final String DEFAULT_USER_AGENT = buildDefaultUserAgent(); + private JmeterRequestHeadersSupport() { } @@ -28,8 +35,7 @@ static void prepareFromSampler(Request request, boolean useKeepAlive) { } request.attribute(ATTR_USE_KEEPALIVE, useKeepAlive); applyConnectionHeader(request, useKeepAlive); - // TODO: HC4 sends explicit empty User-Agent when none is configured (disableDefaultUserAgent). - // prepareEmptyUserAgentHeader(request); + applyDefaultUserAgentHeader(request); } /** @@ -54,7 +60,6 @@ static HttpFields headersForSampleResult(Request request) { } HttpFields.Mutable merged = HttpFields.build(request.getHeaders()); restoreConnectionHeaderForSample(request, merged); - // restoreEmptyUserAgentForSample(request, merged); return merged; } @@ -73,6 +78,39 @@ private static void applyConnectionHeader(Request request, boolean useKeepAlive) } } + + /** + * Matches {@code HTTPHC4Impl}: when no {@code User-Agent} is configured, send a plugin default + * unless {@code httpclient4.default_user_agent_disabled=true}. + */ + private static void applyDefaultUserAgentHeader(Request request) { + if (isDefaultUserAgentDisabled()) { + return; + } + HttpFields.Mutable mutableHeaders = mutableHeaders(request); + if (mutableHeaders == null || mutableHeaders.contains(HttpHeader.USER_AGENT)) { + return; + } + mutableHeaders.put(HttpHeader.USER_AGENT, DEFAULT_USER_AGENT); + } + + static boolean isDefaultUserAgentDisabled() { + return JMeterUtils.getPropDefault(DEFAULT_USER_AGENT_PROPERTY, false); + } + + static String defaultUserAgent() { + return DEFAULT_USER_AGENT; + } + + private static String buildDefaultUserAgent() { + Package pkg = JmeterRequestHeadersSupport.class.getPackage(); + String version = pkg != null ? pkg.getImplementationVersion() : null; + if (StringUtils.isBlank(version)) { + return "BlazeMeter HTTP"; + } + return "BlazeMeter HTTP/" + version; + } + private static void restoreConnectionHeaderForSample( Request request, HttpFields.Mutable headers) { Object useKeepAlive = request.getAttributes().get(ATTR_USE_KEEPALIVE); diff --git a/src/test/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupportTest.java b/src/test/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupportTest.java index b5079a3..2d1e562 100644 --- a/src/test/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupportTest.java +++ b/src/test/java/com/blazemeter/jmeter/http2/core/JmeterRequestHeadersSupportTest.java @@ -4,17 +4,28 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import com.blazemeter.jmeter.http2.HTTP2TestBase; import java.util.HashMap; import java.util.Map; import org.apache.jmeter.protocol.http.util.HTTPConstants; +import org.apache.jmeter.util.JMeterUtils; import org.eclipse.jetty.client.Request; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; +import org.junit.After; import org.junit.Test; import org.mockito.Mockito; -public class JmeterRequestHeadersSupportTest { +public class JmeterRequestHeadersSupportTest extends HTTP2TestBase { + + private static final String UA_DISABLED_PROP = + JmeterRequestHeadersSupport.DEFAULT_USER_AGENT_PROPERTY; + + @After + public void clearUserAgentProperty() { + JMeterUtils.getJMeterProperties().remove(UA_DISABLED_PROP); + } private static Request mockRequest(HttpFields.Mutable headers) { Map attributes = new HashMap<>(); @@ -74,4 +85,50 @@ public void prepareFromSamplerDoesNotOverrideExplicitConnectionHeader() { assertThat(headers.get(HttpHeader.CONNECTION)).isEqualTo("Upgrade"); } -} \ No newline at end of file + + @Test + public void prepareFromSamplerAddsDefaultUserAgentWhenMissing() { + HttpFields.Mutable headers = HttpFields.build(); + Request request = mockRequest(headers); + + JmeterRequestHeadersSupport.prepareFromSampler(request, true); + + assertThat(headers.get(HttpHeader.USER_AGENT)) + .isEqualTo(JmeterRequestHeadersSupport.defaultUserAgent()); + assertThat(headers.get(HttpHeader.USER_AGENT)).startsWith("BlazeMeter HTTP"); + } + + @Test + public void prepareFromSamplerDoesNotOverrideConfiguredUserAgent() { + HttpFields.Mutable headers = HttpFields.build() + .add(HttpHeader.USER_AGENT, "CustomAgent/1.0"); + Request request = mockRequest(headers); + + JmeterRequestHeadersSupport.prepareFromSampler(request, true); + + assertThat(headers.get(HttpHeader.USER_AGENT)).isEqualTo("CustomAgent/1.0"); + } + + @Test + public void prepareFromSamplerKeepsEmptyUserAgentFromHeaderManager() { + HttpFields.Mutable headers = HttpFields.build() + .add(HttpHeader.USER_AGENT, ""); + Request request = mockRequest(headers); + + JmeterRequestHeadersSupport.prepareFromSampler(request, true); + + assertThat(headers.contains(HttpHeader.USER_AGENT)).isTrue(); + assertThat(headers.get(HttpHeader.USER_AGENT)).isEmpty(); + } + + @Test + public void prepareFromSamplerOmitsDefaultUserAgentWhenPropertyDisabled() { + JMeterUtils.setProperty(UA_DISABLED_PROP, "true"); + HttpFields.Mutable headers = HttpFields.build(); + Request request = mockRequest(headers); + + JmeterRequestHeadersSupport.prepareFromSampler(request, true); + + assertThat(headers.contains(HttpHeader.USER_AGENT)).isFalse(); + } +}