1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.testing.external;
28
29 import java.util.Objects;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.TimeoutException;
33
34 import javax.net.ssl.SSLContext;
35
36 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
37 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
38 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
39 import org.apache.hc.client5.http.auth.AuthScope;
40 import org.apache.hc.client5.http.auth.Credentials;
41 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
42 import org.apache.hc.client5.http.config.RequestConfig;
43 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
44 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
45 import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
46 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
47 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
48 import org.apache.hc.client5.http.protocol.HttpClientContext;
49 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
50 import org.apache.hc.core5.http.HeaderElements;
51 import org.apache.hc.core5.http.HttpHeaders;
52 import org.apache.hc.core5.http.HttpHost;
53 import org.apache.hc.core5.http.HttpRequest;
54 import org.apache.hc.core5.http.HttpResponse;
55 import org.apache.hc.core5.http.HttpStatus;
56 import org.apache.hc.core5.http2.HttpVersionPolicy;
57 import org.apache.hc.core5.ssl.SSLContexts;
58 import org.apache.hc.core5.util.TextUtils;
59 import org.apache.hc.core5.util.TimeValue;
60 import org.apache.hc.core5.util.Timeout;
61
62 public class HttpAsyncClientCompatibilityTest {
63
64 public static void main(final String... args) throws Exception {
65 final HttpAsyncClientCompatibilityTestlientCompatibilityTest.html#HttpAsyncClientCompatibilityTest">HttpAsyncClientCompatibilityTest[] tests = new HttpAsyncClientCompatibilityTest[] {
66 new HttpAsyncClientCompatibilityTest(
67 HttpVersionPolicy.FORCE_HTTP_1,
68 new HttpHost("http", "localhost", 8080), null, null),
69 new HttpAsyncClientCompatibilityTest(
70 HttpVersionPolicy.FORCE_HTTP_1,
71 new HttpHost("http", "test-httpd", 8080), new HttpHost("localhost", 8888), null),
72 new HttpAsyncClientCompatibilityTest(
73 HttpVersionPolicy.FORCE_HTTP_1,
74 new HttpHost("http", "test-httpd", 8080), new HttpHost("localhost", 8889),
75 new UsernamePasswordCredentials("squid", "nopassword".toCharArray())),
76 new HttpAsyncClientCompatibilityTest(
77 HttpVersionPolicy.FORCE_HTTP_1,
78 new HttpHost("https", "localhost", 8443), null, null),
79 new HttpAsyncClientCompatibilityTest(
80 HttpVersionPolicy.FORCE_HTTP_1,
81 new HttpHost("https", "test-httpd", 8443), new HttpHost("localhost", 8888), null),
82 new HttpAsyncClientCompatibilityTest(
83 HttpVersionPolicy.FORCE_HTTP_1,
84 new HttpHost("https", "test-httpd", 8443), new HttpHost("localhost", 8889),
85 new UsernamePasswordCredentials("squid", "nopassword".toCharArray())),
86 new HttpAsyncClientCompatibilityTest(
87 HttpVersionPolicy.FORCE_HTTP_2,
88 new HttpHost("http", "localhost", 8080), null, null),
89 new HttpAsyncClientCompatibilityTest(
90 HttpVersionPolicy.FORCE_HTTP_2,
91 new HttpHost("https", "localhost", 8443), null, null),
92 new HttpAsyncClientCompatibilityTest(
93 HttpVersionPolicy.NEGOTIATE,
94 new HttpHost("https", "test-httpd", 8443), new HttpHost("localhost", 8888), null),
95 new HttpAsyncClientCompatibilityTest(
96 HttpVersionPolicy.NEGOTIATE,
97 new HttpHost("https", "test-httpd", 8443), new HttpHost("localhost", 8889),
98 new UsernamePasswordCredentials("squid", "nopassword".toCharArray()))
99 };
100 for (final HttpAsyncClientCompatibilityTest test: tests) {
101 try {
102 test.execute();
103 } finally {
104 test.shutdown();
105 }
106 }
107 }
108
109 private static final Timeout TIMEOUT = Timeout.ofSeconds(5);
110
111 private final HttpVersionPolicy versionPolicy;
112 private final HttpHost target;
113 private final HttpHost proxy;
114 private final BasicCredentialsProvider credentialsProvider;
115 private final PoolingAsyncClientConnectionManager connManager;
116 private final CloseableHttpAsyncClient client;
117
118 HttpAsyncClientCompatibilityTest(
119 final HttpVersionPolicy versionPolicy,
120 final HttpHost target,
121 final HttpHost proxy,
122 final Credentials proxyCreds) throws Exception {
123 this.versionPolicy = versionPolicy;
124 this.target = target;
125 this.proxy = proxy;
126 this.credentialsProvider = new BasicCredentialsProvider();
127 final RequestConfig requestConfig = RequestConfig.custom()
128 .setProxy(proxy)
129 .build();
130 if (proxy != null && proxyCreds != null) {
131 this.credentialsProvider.setCredentials(new AuthScope(proxy), proxyCreds);
132 }
133 final SSLContext sslContext = SSLContexts.custom()
134 .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
135 this.connManager = PoolingAsyncClientConnectionManagerBuilder.create()
136 .setTlsStrategy(new DefaultClientTlsStrategy(sslContext))
137 .build();
138 this.client = HttpAsyncClients.custom()
139 .setVersionPolicy(this.versionPolicy)
140 .setConnectionManager(this.connManager)
141 .setProxy(this.proxy)
142 .setDefaultRequestConfig(requestConfig)
143 .build();
144 }
145
146 void shutdown() throws Exception {
147 client.close();
148 }
149
150 enum TestResult {OK, NOK}
151
152 private void logResult(final TestResult result,
153 final HttpRequest request,
154 final HttpResponse response,
155 final String message) {
156 final StringBuilder buf = new StringBuilder();
157 buf.append(result);
158 if (buf.length() == 2) {
159 buf.append(" ");
160 }
161 buf.append(": ");
162 if (response != null) {
163 buf.append(response.getVersion()).append(" ");
164 } else {
165 buf.append(versionPolicy).append(" ");
166 }
167 buf.append(target);
168 if (proxy != null) {
169 buf.append(" via ").append(proxy);
170 }
171 buf.append(": ");
172 buf.append(request.getMethod()).append(" ").append(request.getRequestUri());
173 if (message != null && !TextUtils.isBlank(message)) {
174 buf.append(" -> ").append(message);
175 }
176 System.out.println(buf);
177 }
178
179 void execute() throws Exception {
180
181 client.start();
182
183 {
184 final HttpClientContext context = HttpClientContext.create();
185 context.setCredentialsProvider(credentialsProvider);
186
187 final SimpleHttpRequest options = SimpleRequestBuilder.options()
188 .setHttpHost(target)
189 .setPath("*")
190 .build();
191 final Future<SimpleHttpResponse> future = client.execute(options, context, null);
192 try {
193 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
194 final int code = response.getCode();
195 if (code == HttpStatus.SC_OK) {
196 logResult(TestResult.OK, options, response, Objects.toString(response.getFirstHeader("server")));
197 } else {
198 logResult(TestResult.NOK, options, response, "(status " + code + ")");
199 }
200 } catch (final ExecutionException ex) {
201 final Throwable cause = ex.getCause();
202 logResult(TestResult.NOK, options, null, "(" + cause.getMessage() + ")");
203 } catch (final TimeoutException ex) {
204 logResult(TestResult.NOK, options, null, "(time out)");
205 }
206 }
207
208 {
209 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
210 final HttpClientContext context = HttpClientContext.create();
211 context.setCredentialsProvider(credentialsProvider);
212
213 final String[] requestUris = new String[] {"/", "/news.html", "/status.html"};
214 for (final String requestUri: requestUris) {
215 final SimpleHttpRequest httpGet = SimpleRequestBuilder.get()
216 .setHttpHost(target)
217 .setPath(requestUri)
218 .build();
219 final Future<SimpleHttpResponse> future = client.execute(httpGet, context, null);
220 try {
221 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
222 final int code = response.getCode();
223 if (code == HttpStatus.SC_OK) {
224 logResult(TestResult.OK, httpGet, response, "200");
225 } else {
226 logResult(TestResult.NOK, httpGet, response, "(status " + code + ")");
227 }
228 } catch (final ExecutionException ex) {
229 final Throwable cause = ex.getCause();
230 logResult(TestResult.NOK, httpGet, null, "(" + cause.getMessage() + ")");
231 } catch (final TimeoutException ex) {
232 logResult(TestResult.NOK, httpGet, null, "(time out)");
233 }
234 }
235 }
236
237 {
238 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
239 credentialsProvider.setCredentials(
240 new AuthScope("http", "otherhost", -1, "Restricted Files", null),
241 new UsernamePasswordCredentials("testuser", "nopassword".toCharArray()));
242 final HttpClientContext context = HttpClientContext.create();
243 context.setCredentialsProvider(credentialsProvider);
244
245 final SimpleHttpRequest httpGetSecret = SimpleRequestBuilder.get()
246 .setHttpHost(target)
247 .setPath("/private/big-secret.txt")
248 .build();
249 final Future<SimpleHttpResponse> future = client.execute(httpGetSecret, context, null);
250 try {
251 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
252 final int code = response.getCode();
253 if (code == HttpStatus.SC_UNAUTHORIZED) {
254 logResult(TestResult.OK, httpGetSecret, response, "401 (wrong target auth scope)");
255 } else {
256 logResult(TestResult.NOK, httpGetSecret, response, "(status " + code + ")");
257 }
258 } catch (final ExecutionException ex) {
259 final Throwable cause = ex.getCause();
260 logResult(TestResult.NOK, httpGetSecret, null, "(" + cause.getMessage() + ")");
261 } catch (final TimeoutException ex) {
262 logResult(TestResult.NOK, httpGetSecret, null, "(time out)");
263 }
264 }
265
266 {
267 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
268 credentialsProvider.setCredentials(
269 new AuthScope(target),
270 new UsernamePasswordCredentials("testuser", "wrong password".toCharArray()));
271 final HttpClientContext context = HttpClientContext.create();
272 context.setCredentialsProvider(credentialsProvider);
273
274 final SimpleHttpRequest httpGetSecret = SimpleRequestBuilder.get()
275 .setHttpHost(target)
276 .setPath("/private/big-secret.txt")
277 .build();
278 final Future<SimpleHttpResponse> future = client.execute(httpGetSecret, context, null);
279 try {
280 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
281 final int code = response.getCode();
282 if (code == HttpStatus.SC_UNAUTHORIZED) {
283 logResult(TestResult.OK, httpGetSecret, response, "401 (wrong target creds)");
284 } else {
285 logResult(TestResult.NOK, httpGetSecret, response, "(status " + code + ")");
286 }
287 } catch (final ExecutionException ex) {
288 final Throwable cause = ex.getCause();
289 logResult(TestResult.NOK, httpGetSecret, null, "(" + cause.getMessage() + ")");
290 } catch (final TimeoutException ex) {
291 logResult(TestResult.NOK, httpGetSecret, null, "(time out)");
292 }
293 }
294
295 {
296 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
297 credentialsProvider.setCredentials(
298 new AuthScope(target),
299 new UsernamePasswordCredentials("testuser", "nopassword".toCharArray()));
300 final HttpClientContext context = HttpClientContext.create();
301 context.setCredentialsProvider(credentialsProvider);
302
303 final SimpleHttpRequest httpGetSecret = SimpleRequestBuilder.get()
304 .setHttpHost(target)
305 .setPath("/private/big-secret.txt")
306 .build();
307 final Future<SimpleHttpResponse> future = client.execute(httpGetSecret, context, null);
308 try {
309 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
310 final int code = response.getCode();
311 if (code == HttpStatus.SC_OK) {
312 logResult(TestResult.OK, httpGetSecret, response, "200 (correct target creds)");
313 } else {
314 logResult(TestResult.NOK, httpGetSecret, response, "(status " + code + ")");
315 }
316 } catch (final ExecutionException ex) {
317 final Throwable cause = ex.getCause();
318 logResult(TestResult.NOK, httpGetSecret, null, "(" + cause.getMessage() + ")");
319 } catch (final TimeoutException ex) {
320 logResult(TestResult.NOK, httpGetSecret, null, "(time out)");
321 }
322 }
323
324 if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_1)
325 {
326 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
327 credentialsProvider.setCredentials(
328 new AuthScope(target),
329 new UsernamePasswordCredentials("testuser", "nopassword".toCharArray()));
330 final HttpClientContext context = HttpClientContext.create();
331 context.setCredentialsProvider(credentialsProvider);
332
333 final SimpleHttpRequest httpGetSecret = SimpleRequestBuilder.get()
334 .setHttpHost(target)
335 .setPath("/private/big-secret.txt")
336 .build();
337 httpGetSecret.setHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE);
338 final Future<SimpleHttpResponse> future = client.execute(httpGetSecret, context, null);
339 try {
340 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
341 final int code = response.getCode();
342 if (code == HttpStatus.SC_OK) {
343 logResult(TestResult.OK, httpGetSecret, response, "200 (correct target creds / no keep-alive)");
344 } else {
345 logResult(TestResult.NOK, httpGetSecret, response, "(status " + code + ")");
346 }
347 } catch (final ExecutionException ex) {
348 final Throwable cause = ex.getCause();
349 logResult(TestResult.NOK, httpGetSecret, null, "(" + cause.getMessage() + ")");
350 } catch (final TimeoutException ex) {
351 logResult(TestResult.NOK, httpGetSecret, null, "(time out)");
352 }
353 }
354 }
355
356 }