diff --git a/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java b/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java
index 78cf8adc8ff..608c6019ddb 100644
--- a/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java
+++ b/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java
@@ -16,6 +16,35 @@ public class ArthasConstants {
public static final int MAX_HTTP_CONTENT_LENGTH = 1024 * 1024 * 10;
+ /**
+ * System property to override the max HTTP content length used by the
+ * tunnel-client when proxying responses (e.g. JFR recording downloads)
+ * back to the tunnel-server. The value is in bytes; default is
+ * {@link #MAX_HTTP_CONTENT_LENGTH} (10 MB). See issue #3034.
+ */
+ public static final String TUNNEL_CLIENT_MAX_HTTP_CONTENT_LENGTH_PROPERTY = "arthas.tunnel.client.max-http-content-length";
+
+ /**
+ * Resolve the configured tunnel-client max HTTP content length. Falls back
+ * to {@link #MAX_HTTP_CONTENT_LENGTH} when the system property is unset,
+ * non-numeric, or non-positive.
+ */
+ public static int getTunnelClientMaxHttpContentLength() {
+ String value = System.getProperty(TUNNEL_CLIENT_MAX_HTTP_CONTENT_LENGTH_PROPERTY);
+ if (value == null || value.isEmpty()) {
+ return MAX_HTTP_CONTENT_LENGTH;
+ }
+ try {
+ int parsed = Integer.parseInt(value.trim());
+ if (parsed > 0) {
+ return parsed;
+ }
+ } catch (NumberFormatException ignore) {
+ // fall through to default
+ }
+ return MAX_HTTP_CONTENT_LENGTH;
+ }
+
public static final String ARTHAS_OUTPUT = "arthas-output";
public static final String APP_NAME = "app-name";
diff --git a/tunnel-client/pom.xml b/tunnel-client/pom.xml
index 968eeb74b67..506ce5bd039 100644
--- a/tunnel-client/pom.xml
+++ b/tunnel-client/pom.xml
@@ -57,6 +57,16 @@
netty-codec-http
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
diff --git a/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/ProxyClient.java b/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/ProxyClient.java
index 33b93e0b8d6..c7c42f49967 100644
--- a/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/ProxyClient.java
+++ b/tunnel-client/src/main/java/com/alibaba/arthas/tunnel/client/ProxyClient.java
@@ -60,7 +60,8 @@ public SimpleHttpResponse query(String targetUrl) throws InterruptedException {
@Override
protected void initChannel(LocalChannel ch) {
ChannelPipeline p = ch.pipeline();
- p.addLast(new HttpClientCodec(), new HttpObjectAggregator(ArthasConstants.MAX_HTTP_CONTENT_LENGTH),
+ p.addLast(new HttpClientCodec(),
+ new HttpObjectAggregator(ArthasConstants.getTunnelClientMaxHttpContentLength()),
new HttpProxyClientHandler(httpResponsePromise));
}
});
diff --git a/tunnel-client/src/test/java/com/taobao/arthas/common/ArthasConstantsTest.java b/tunnel-client/src/test/java/com/taobao/arthas/common/ArthasConstantsTest.java
new file mode 100644
index 00000000000..f33f9756408
--- /dev/null
+++ b/tunnel-client/src/test/java/com/taobao/arthas/common/ArthasConstantsTest.java
@@ -0,0 +1,67 @@
+package com.taobao.arthas.common;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for the configurable tunnel-client max HTTP content length introduced
+ * for issue #3034 ("Unable to download JFR recordings larger than 10MB via
+ * Tunnel Server").
+ */
+public class ArthasConstantsTest {
+
+ private static final String PROPERTY = ArthasConstants.TUNNEL_CLIENT_MAX_HTTP_CONTENT_LENGTH_PROPERTY;
+
+ private String originalValue;
+
+ @Before
+ public void saveProperty() {
+ originalValue = System.getProperty(PROPERTY);
+ System.clearProperty(PROPERTY);
+ }
+
+ @After
+ public void restoreProperty() {
+ if (originalValue == null) {
+ System.clearProperty(PROPERTY);
+ } else {
+ System.setProperty(PROPERTY, originalValue);
+ }
+ }
+
+ @Test
+ public void defaultsToTenMegabytesWhenPropertyMissing() {
+ assertEquals(ArthasConstants.MAX_HTTP_CONTENT_LENGTH,
+ ArthasConstants.getTunnelClientMaxHttpContentLength());
+ }
+
+ @Test
+ public void honoursConfiguredPropertyValue() {
+ int oneHundredMb = 100 * 1024 * 1024;
+ System.setProperty(PROPERTY, Integer.toString(oneHundredMb));
+
+ assertEquals(oneHundredMb, ArthasConstants.getTunnelClientMaxHttpContentLength());
+ }
+
+ @Test
+ public void fallsBackToDefaultWhenPropertyIsNotANumber() {
+ System.setProperty(PROPERTY, "not-a-number");
+
+ assertEquals(ArthasConstants.MAX_HTTP_CONTENT_LENGTH,
+ ArthasConstants.getTunnelClientMaxHttpContentLength());
+ }
+
+ @Test
+ public void fallsBackToDefaultWhenPropertyIsNotPositive() {
+ System.setProperty(PROPERTY, "0");
+ assertEquals(ArthasConstants.MAX_HTTP_CONTENT_LENGTH,
+ ArthasConstants.getTunnelClientMaxHttpContentLength());
+
+ System.setProperty(PROPERTY, "-1");
+ assertEquals(ArthasConstants.MAX_HTTP_CONTENT_LENGTH,
+ ArthasConstants.getTunnelClientMaxHttpContentLength());
+ }
+}