2727package org .apache .hc .client5 .http .impl .classic ;
2828
2929import java .io .IOException ;
30+ import java .lang .reflect .Field ;
31+ import java .net .ProxySelector ;
3032
3133import org .apache .hc .client5 .http .classic .ExecChain ;
3234import org .apache .hc .client5 .http .classic .ExecChainHandler ;
35+ import org .apache .hc .client5 .http .impl .routing .DefaultProxyRoutePlanner ;
36+ import org .apache .hc .client5 .http .impl .routing .DefaultRoutePlanner ;
37+ import org .apache .hc .client5 .http .impl .routing .SystemDefaultRoutePlanner ;
38+ import org .apache .hc .client5 .http .protocol .HttpClientContext ;
39+ import org .apache .hc .client5 .http .routing .HttpRoutePlanner ;
3340import org .apache .hc .core5 .http .ClassicHttpRequest ;
3441import org .apache .hc .core5 .http .ClassicHttpResponse ;
3542import org .apache .hc .core5 .http .HttpException ;
43+ import org .apache .hc .core5 .http .HttpHost ;
44+ import org .apache .hc .core5 .http .protocol .HttpContext ;
45+ import org .junit .jupiter .api .Assertions ;
3646import org .junit .jupiter .api .Test ;
3747
3848class TestHttpClientBuilder {
@@ -66,4 +76,87 @@ public ClassicHttpResponse execute(
6676 return chain .proceed (request , scope );
6777 }
6878 }
79+
80+ @ Test
81+ void testDefaultUsesSystemDefaultRoutePlanner () throws Exception {
82+ try (final InternalHttpClient client = (InternalHttpClient ) HttpClients .custom ().build ()) {
83+ final Object planner = getPrivateField (client , "routePlanner" );
84+ Assertions .assertNotNull (planner );
85+ Assertions .assertInstanceOf (SystemDefaultRoutePlanner .class , planner , "Default should be SystemDefaultRoutePlanner (auto-detect proxies)" );
86+ }
87+ }
88+
89+ @ Test
90+ void testDisableProxyAutodetectionFallsBackToDefaultRoutePlanner () throws Exception {
91+ try (final InternalHttpClient client = (InternalHttpClient ) HttpClients .custom ()
92+ .disableProxyAutodetection ()
93+ .build ()) {
94+ final Object planner = getPrivateField (client , "routePlanner" );
95+ Assertions .assertNotNull (planner );
96+ Assertions .assertInstanceOf (DefaultRoutePlanner .class , planner , "disableProxyAutodetection() should restore DefaultRoutePlanner" );
97+ }
98+ }
99+
100+ @ Test
101+ void testExplicitProxyWinsOverAutodetection () throws Exception {
102+ try (final InternalHttpClient client = (InternalHttpClient ) HttpClients .custom ()
103+ .setProxy (new HttpHost ("http" , "proxy.local" , 8080 ))
104+ .build ()) {
105+ final Object planner = getPrivateField (client , "routePlanner" );
106+ Assertions .assertNotNull (planner );
107+ Assertions .assertInstanceOf (DefaultProxyRoutePlanner .class , planner , "Explicit proxy must take precedence" );
108+ }
109+ }
110+
111+ @ Test
112+ void testCustomRoutePlannerIsRespected () throws Exception {
113+ final HttpRoutePlanner custom = new HttpRoutePlanner () {
114+ @ Override
115+ public org .apache .hc .client5 .http .HttpRoute determineRoute (
116+ final HttpHost host , final HttpContext context ) {
117+ // trivial, never used in this test
118+ return new org .apache .hc .client5 .http .HttpRoute (host );
119+ }
120+ };
121+ try (final InternalHttpClient client = (InternalHttpClient ) HttpClients .custom ()
122+ .setRoutePlanner (custom )
123+ .build ()) {
124+ final Object planner = getPrivateField (client , "routePlanner" );
125+ Assertions .assertSame (custom , planner , "Custom route planner must be used as-is" );
126+ }
127+ }
128+
129+ @ Test
130+ void testProvidedProxySelectorIsUsedBySystemDefaultRoutePlanner () throws Exception {
131+ class TouchProxySelector extends ProxySelector {
132+ volatile boolean touched = false ;
133+ @ Override
134+ public java .util .List <java .net .Proxy > select (final java .net .URI uri ) {
135+ touched = true ;
136+ return java .util .Collections .singletonList (java .net .Proxy .NO_PROXY );
137+ }
138+ @ Override
139+ public void connectFailed (final java .net .URI uri , final java .net .SocketAddress sa , final IOException ioe ) { }
140+ }
141+ final TouchProxySelector selector = new TouchProxySelector ();
142+
143+ try (final InternalHttpClient client = (InternalHttpClient ) HttpClients .custom ()
144+ .setProxySelector (selector )
145+ .build ()) {
146+ final Object planner = getPrivateField (client , "routePlanner" );
147+ Assertions .assertInstanceOf (SystemDefaultRoutePlanner .class , planner );
148+
149+ // Call determineRoute on the planner directly to avoid making a real request
150+ final SystemDefaultRoutePlanner sdrp = (SystemDefaultRoutePlanner ) planner ;
151+ sdrp .determineRoute (new HttpHost ("http" , "example.com" , 80 ), HttpClientContext .create ());
152+
153+ Assertions .assertTrue (selector .touched , "Provided ProxySelector should be consulted" );
154+ }
155+ }
156+
157+ private static Object getPrivateField (final Object target , final String name ) throws Exception {
158+ final Field f = target .getClass ().getDeclaredField (name );
159+ f .setAccessible (true );
160+ return f .get (target );
161+ }
69162}
0 commit comments