Skip to content

Commit bd6f444

Browse files
committed
Fix Netty interception when launched in Docker
Within static fields, it was not possible to access project dependencies at runtime. Specifically, when launching the spring petclinic microservices demo, the API gateway that uses HttpClient crashed because reactor.netty.transport.ProxyProvider wasn't available when evaluating the static field. I'm fairly sure this is due to the app being launched with org.springframework.boot.loader.JarLauncher, which reconfigures the classpath during startup. To work around this, we defer loading these inaccessible types until the intercepted HttpClient constructor. That probably creates a very minor performance hit, but nothing significant. If this does become significant in future, we could probably preserve the fields, and make constructor initialization a one-off, but it's more complicated and risky, so let's not bother for now. Only matters if you're creating very very large numbers of HttpClients in a hot loop, which seems unlikely.
1 parent 400d973 commit bd6f444

File tree

1 file changed

+27
-30
lines changed

1 file changed

+27
-30
lines changed

src/main/java/tech/httptoolkit/javaagent/advice/reactornetty/ReactorNettyResetAllConfigAdvice.java

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,36 @@
1313

1414
public class ReactorNettyResetAllConfigAdvice {
1515

16-
public static final ProxyProvider agentProxyProvider = ProxyProvider.builder()
17-
.type(ProxyProvider.Proxy.HTTP)
18-
.address(new InetSocketAddress(
19-
HttpProxyAgent.getAgentProxyHost(),
20-
HttpProxyAgent.getAgentProxyPort()
21-
))
22-
.build();
23-
24-
public static final SslProvider agentSslProvider;
25-
26-
public static final Field configSslField;
27-
public static final Field proxyProviderField;
16+
// Netty's HTTP Client works by creating a new client subclass, and passing the existing client's
17+
// config. We hook that here: we rewrite the config whenever it's used, affecting all clients
18+
// involved, and in practice anybody using config anywhere.
2819

29-
static {
30-
try {
31-
// Initialize our intercepted SSL provider:
32-
agentSslProvider = SslProvider.builder()
33-
.sslContext(
20+
@Advice.OnMethodEnter
21+
public static void beforeConstructor(
22+
@Advice.Argument(value=0) HttpClientConfig baseHttpConfig
23+
) throws Exception {
24+
// It would be nice to do this setup statically, but due to how some classloader configs work (e.g. Spring) it
25+
// seems this can fail when run in a static block, so we just repeat the process for every interception:
26+
final SslProvider agentSslProvider = SslProvider.builder()
27+
.sslContext(
3428
SslContextBuilder
35-
.forClient()
36-
.trustManager(HttpProxyAgent.getInterceptedTrustManagerFactory())
37-
.build()
38-
).build();
29+
.forClient()
30+
.trustManager(HttpProxyAgent.getInterceptedTrustManagerFactory())
31+
.build()
32+
).build();
33+
34+
final ProxyProvider agentProxyProvider = ProxyProvider.builder()
35+
.type(ProxyProvider.Proxy.HTTP)
36+
.address(new InetSocketAddress(
37+
HttpProxyAgent.getAgentProxyHost(),
38+
HttpProxyAgent.getAgentProxyPort()
39+
))
40+
.build();
41+
42+
Field configSslField;
43+
Field proxyProviderField;
3944

45+
try {
4046
// Rewrite the fields we want to mess with in the client config:
4147
configSslField = HttpClientConfig.class.getDeclaredField("sslProvider");
4248
configSslField.setAccessible(true);
@@ -46,16 +52,7 @@ public class ReactorNettyResetAllConfigAdvice {
4652
} catch (Exception e) {
4753
throw new RuntimeException(e);
4854
}
49-
}
50-
51-
// Netty's HTTP Client works by creating a new client subclass, and passing the existing client's
52-
// config. We hook that here: we rewrite the config whenever it's used, affecting all clients
53-
// involved, and in practice anybody using config anywhere.
5455

55-
@Advice.OnMethodEnter
56-
public static void beforeConstructor(
57-
@Advice.Argument(value=0) HttpClientConfig baseHttpConfig
58-
) throws Exception {
5956
configSslField.set(baseHttpConfig, agentSslProvider);
6057
proxyProviderField.set(baseHttpConfig, agentProxyProvider);
6158
}

0 commit comments

Comments
 (0)