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()); + } +}