27
27
package org .apache .hc .client5 .http .impl .classic ;
28
28
29
29
import java .io .IOException ;
30
+ import java .lang .reflect .Field ;
31
+ import java .net .ProxySelector ;
30
32
31
33
import org .apache .hc .client5 .http .classic .ExecChain ;
32
34
import 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 ;
33
40
import org .apache .hc .core5 .http .ClassicHttpRequest ;
34
41
import org .apache .hc .core5 .http .ClassicHttpResponse ;
35
42
import 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 ;
36
46
import org .junit .jupiter .api .Test ;
37
47
38
48
class TestHttpClientBuilder {
@@ -66,4 +76,87 @@ public ClassicHttpResponse execute(
66
76
return chain .proceed (request , scope );
67
77
}
68
78
}
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
+ }
69
162
}
0 commit comments