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.async;
28
29 import java.util.concurrent.Future;
30
31 import org.apache.hc.client5.http.HttpRoute;
32 import org.apache.hc.client5.http.UserTokenHandler;
33 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
34 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
35 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
36 import org.apache.hc.client5.http.config.RequestConfig;
37 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
38 import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
39 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
40 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
41 import org.apache.hc.client5.http.protocol.HttpClientContext;
42 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
43 import org.apache.hc.client5.testing.SSLTestContexts;
44 import org.apache.hc.core5.function.Supplier;
45 import org.apache.hc.core5.http.ContentType;
46 import org.apache.hc.core5.http.EndpointDetails;
47 import org.apache.hc.core5.http.HttpException;
48 import org.apache.hc.core5.http.HttpHost;
49 import org.apache.hc.core5.http.HttpResponse;
50 import org.apache.hc.core5.http.HttpStatus;
51 import org.apache.hc.core5.http.config.Http1Config;
52 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
53 import org.apache.hc.core5.http.protocol.BasicHttpContext;
54 import org.apache.hc.core5.http.protocol.HttpContext;
55 import org.apache.hc.core5.http.protocol.HttpCoreContext;
56 import org.apache.hc.core5.net.URIAuthority;
57 import org.junit.Assert;
58 import org.junit.Rule;
59 import org.junit.Test;
60 import org.junit.rules.ExternalResource;
61
62 public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTestBase<CloseableHttpAsyncClient> {
63
64 protected HttpAsyncClientBuilder clientBuilder;
65 protected PoolingAsyncClientConnectionManager connManager;
66
67 @Rule
68 public ExternalResource connManagerResource = new ExternalResource() {
69
70 @Override
71 protected void before() throws Throwable {
72 connManager = PoolingAsyncClientConnectionManagerBuilder.create()
73 .setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
74 .build();
75 }
76
77 @Override
78 protected void after() {
79 if (connManager != null) {
80 connManager.close();
81 connManager = null;
82 }
83 }
84
85 };
86
87 @Rule
88 public ExternalResource clientBuilderResource = new ExternalResource() {
89
90 @Override
91 protected void before() throws Throwable {
92 clientBuilder = HttpAsyncClientBuilder.create()
93 .setDefaultRequestConfig(RequestConfig.custom()
94 .setConnectTimeout(TIMEOUT)
95 .setConnectionRequestTimeout(TIMEOUT)
96 .build())
97 .setConnectionManager(connManager);
98 }
99
100 };
101
102 @Override
103 protected CloseableHttpAsyncClient createClient() throws Exception {
104 return clientBuilder.build();
105 }
106
107 @Override
108 public HttpHost start() throws Exception {
109 return super.start(null, Http1Config.DEFAULT);
110 }
111
112 @Test
113 public void testStatefulConnections() throws Exception {
114 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
115
116 @Override
117 public AsyncServerExchangeHandler get() {
118 return new AbstractSimpleServerExchangeHandler() {
119
120 @Override
121 protected SimpleHttpResponse handle(
122 final SimpleHttpRequest request,
123 final HttpCoreContext context) throws HttpException {
124 final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
125 response.setBody("Whatever", ContentType.TEXT_PLAIN);
126 return response;
127 }
128 };
129 }
130
131 });
132
133 final UserTokenHandler userTokenHandler = new UserTokenHandler() {
134
135 @Override
136 public Object getUserToken(final HttpRoute route, final HttpContext context) {
137 return context.getAttribute("user");
138 }
139
140 };
141 clientBuilder.setUserTokenHandler(userTokenHandler);
142 final HttpHost target = start();
143
144 final int workerCount = 2;
145 final int requestCount = 5;
146
147 final HttpContext[] contexts = new HttpContext[workerCount];
148 final HttpWorker[] workers = new HttpWorker[workerCount];
149 for (int i = 0; i < contexts.length; i++) {
150 final HttpClientContext context = HttpClientContext.create();
151 contexts[i] = context;
152 workers[i] = new HttpWorker(
153 "user" + i,
154 context, requestCount, target, httpclient);
155 }
156
157 for (final HttpWorker worker : workers) {
158 worker.start();
159 }
160 for (final HttpWorker worker : workers) {
161 worker.join(LONG_TIMEOUT.toMilliseconds());
162 }
163 for (final HttpWorker worker : workers) {
164 final Exception ex = worker.getException();
165 if (ex != null) {
166 throw ex;
167 }
168 Assert.assertEquals(requestCount, worker.getCount());
169 }
170
171 for (final HttpContext context : contexts) {
172 final String state0 = (String) context.getAttribute("r0");
173 Assert.assertNotNull(state0);
174 for (int r = 1; r < requestCount; r++) {
175 Assert.assertEquals(state0, context.getAttribute("r" + r));
176 }
177 }
178
179 }
180
181 static class HttpWorker extends Thread {
182
183 private final String uid;
184 private final HttpClientContext context;
185 private final int requestCount;
186 private final HttpHost target;
187 private final CloseableHttpAsyncClient httpclient;
188
189 private volatile Exception exception;
190 private volatile int count;
191
192 public HttpWorker(
193 final String uid,
194 final HttpClientContext context,
195 final int requestCount,
196 final HttpHost target,
197 final CloseableHttpAsyncClient httpclient) {
198 super();
199 this.uid = uid;
200 this.context = context;
201 this.requestCount = requestCount;
202 this.target = target;
203 this.httpclient = httpclient;
204 this.count = 0;
205 }
206
207 public int getCount() {
208 return count;
209 }
210
211 public Exception getException() {
212 return exception;
213 }
214
215 @Override
216 public void run() {
217 try {
218 context.setAttribute("user", uid);
219 for (int r = 0; r < requestCount; r++) {
220 final SimpleHttpRequest request = SimpleRequestBuilder.get()
221 .setHttpHost(target)
222 .setPath("/")
223 .build();
224 final Future<SimpleHttpResponse> future = httpclient.execute(request, null);
225 future.get();
226
227 count++;
228 final EndpointDetails endpointDetails = context.getEndpointDetails();
229 final String connuid = Integer.toHexString(System.identityHashCode(endpointDetails));
230 context.setAttribute("r" + r, connuid);
231 }
232
233 } catch (final Exception ex) {
234 exception = ex;
235 }
236 }
237
238 }
239
240 @Test
241 public void testRouteSpecificPoolRecylcing() throws Exception {
242 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
243
244 @Override
245 public AsyncServerExchangeHandler get() {
246 return new AbstractSimpleServerExchangeHandler() {
247
248 @Override
249 protected SimpleHttpResponse handle(
250 final SimpleHttpRequest request,
251 final HttpCoreContext context) throws HttpException {
252 final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK);
253 response.setBody("Whatever", ContentType.TEXT_PLAIN);
254 return response;
255 }
256 };
257 }
258
259 });
260
261
262
263
264 final UserTokenHandler userTokenHandler = new UserTokenHandler() {
265
266 @Override
267 public Object getUserToken(final HttpRoute route, final HttpContext context) {
268 return context.getAttribute("user");
269 }
270
271 };
272 clientBuilder.setUserTokenHandler(userTokenHandler);
273
274 final HttpHost target = start();
275 final int maxConn = 2;
276
277 connManager.setMaxTotal(maxConn);
278 connManager.setDefaultMaxPerRoute(maxConn);
279
280
281 final HttpContext context1 = new BasicHttpContext();
282 context1.setAttribute("user", "stuff");
283
284 final SimpleHttpRequest request1 = SimpleRequestBuilder.get()
285 .setHttpHost(target)
286 .setPath("/")
287 .build();
288 final Future<SimpleHttpResponse> future1 = httpclient.execute(request1, context1, null);
289 final HttpResponse response1 = future1.get();
290 Assert.assertNotNull(response1);
291 Assert.assertEquals(200, response1.getCode());
292
293
294
295
296
297 Thread.sleep(100);
298
299
300
301 final HttpContext context2 = new BasicHttpContext();
302
303 final SimpleHttpRequest request2 = SimpleRequestBuilder.get()
304 .setScheme(target.getSchemeName())
305 .setAuthority(new URIAuthority("127.0.0.1", target.getPort()))
306 .setPath("/")
307 .build();
308 final Future<SimpleHttpResponse> future2 = httpclient.execute(request2, context2, null);
309 final HttpResponse response2 = future2.get();
310 Assert.assertNotNull(response2);
311 Assert.assertEquals(200, response2.getCode());
312
313
314
315
316
317 Thread.sleep(100);
318
319
320
321
322
323
324 final HttpContext context3 = new BasicHttpContext();
325
326 final SimpleHttpRequest request3 = SimpleRequestBuilder.get()
327 .setHttpHost(target)
328 .setPath("/")
329 .build();
330 final Future<SimpleHttpResponse> future3 = httpclient.execute(request3, context3, null);
331 final HttpResponse response3 = future3.get();
332 Assert.assertNotNull(response3);
333 Assert.assertEquals(200, response3.getCode());
334 }
335
336 }