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.ArrayList;
30 import java.util.List;
31 import java.util.Objects;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.TimeoutException;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37
38 import javax.net.ssl.SSLContext;
39
40 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
41 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
42 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
43 import org.apache.hc.client5.http.cache.CacheResponseStatus;
44 import org.apache.hc.client5.http.cache.HttpCacheContext;
45 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
46 import org.apache.hc.client5.http.impl.cache.CacheConfig;
47 import org.apache.hc.client5.http.impl.cache.CachingHttpAsyncClients;
48 import org.apache.hc.client5.http.impl.cache.HeapResourceFactory;
49 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
50 import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
51 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
52 import org.apache.hc.core5.http.Header;
53 import org.apache.hc.core5.http.HttpHost;
54 import org.apache.hc.core5.http.HttpRequest;
55 import org.apache.hc.core5.http.HttpStatus;
56 import org.apache.hc.core5.http.HttpVersion;
57 import org.apache.hc.core5.http2.HttpVersionPolicy;
58 import org.apache.hc.core5.ssl.SSLContexts;
59 import org.apache.hc.core5.util.TextUtils;
60 import org.apache.hc.core5.util.TimeValue;
61 import org.apache.hc.core5.util.Timeout;
62
63 public class CachingHttpAsyncClientCompatibilityTest {
64
65 public static void main(final String... args) throws Exception {
66 final CachingHttpAsyncClientCompatibilityTestlientCompatibilityTest.html#CachingHttpAsyncClientCompatibilityTest">CachingHttpAsyncClientCompatibilityTest[] tests = new CachingHttpAsyncClientCompatibilityTest[] {
67 new CachingHttpAsyncClientCompatibilityTest(
68 HttpVersion.HTTP_1_1, new HttpHost("http", "localhost", 8080)),
69 new CachingHttpAsyncClientCompatibilityTest(
70 HttpVersion.HTTP_2_0, new HttpHost("http", "localhost", 8080))
71 };
72 for (final CachingHttpAsyncClientCompatibilityTest test: tests) {
73 try {
74 test.execute();
75 } finally {
76 test.shutdown();
77 }
78 }
79 }
80
81 private static final Timeout TIMEOUT = Timeout.ofSeconds(5);
82
83 private final HttpVersion protocolVersion;
84 private final HttpHost target;
85 private final PoolingAsyncClientConnectionManager connManager;
86 private final CloseableHttpAsyncClient client;
87
88 CachingHttpAsyncClientCompatibilityTest(final HttpVersion protocolVersion, final HttpHost target) throws Exception {
89 this.protocolVersion = protocolVersion;
90 this.target = target;
91 final SSLContext sslContext = SSLContexts.custom()
92 .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
93 this.connManager = PoolingAsyncClientConnectionManagerBuilder.create()
94 .setTlsStrategy(new DefaultClientTlsStrategy(sslContext))
95 .build();
96 this.client = CachingHttpAsyncClients.custom()
97 .setCacheConfig(CacheConfig.custom()
98 .setMaxObjectSize(20480)
99 .build())
100 .setResourceFactory(HeapResourceFactory.INSTANCE)
101 .setVersionPolicy(this.protocolVersion == HttpVersion.HTTP_2 ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1)
102 .setConnectionManager(this.connManager)
103 .build();
104 }
105
106
107 void shutdown() throws Exception {
108 client.close();
109 }
110
111 enum TestResult {OK, NOK}
112
113 private void logResult(final TestResult result, final HttpRequest request, final String message) {
114 final StringBuilder buf = new StringBuilder();
115 buf.append(result);
116 if (buf.length() == 2) {
117 buf.append(" ");
118 }
119 buf.append(": ").append(target);
120 buf.append(": ");
121 buf.append(request.getMethod()).append(" ").append(request.getRequestUri());
122 if (message != null && !TextUtils.isBlank(message)) {
123 buf.append(" -> ").append(message);
124 }
125 System.out.println(buf);
126 }
127
128 void execute() throws Exception {
129
130 client.start();
131
132 {
133 final HttpCacheContext context = HttpCacheContext.create();
134 final SimpleHttpRequest options = SimpleRequestBuilder.options()
135 .setHttpHost(target)
136 .setPath("*")
137 .build();
138 final Future<SimpleHttpResponse> future = client.execute(options, context, null);
139 try {
140 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
141 final int code = response.getCode();
142 if (code == HttpStatus.SC_OK) {
143 logResult(TestResult.OK, options, Objects.toString(response.getFirstHeader("server")));
144 } else {
145 logResult(TestResult.NOK, options, "(status " + code + ")");
146 }
147 } catch (final ExecutionException ex) {
148 final Throwable cause = ex.getCause();
149 logResult(TestResult.NOK, options, "(" + cause.getMessage() + ")");
150 } catch (final TimeoutException ex) {
151 logResult(TestResult.NOK, options, "(time out)");
152 }
153 }
154
155 {
156 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
157 final HttpCacheContext context = HttpCacheContext.create();
158
159 final Pattern linkPattern = Pattern.compile("^<(.*)>;rel=preload$");
160 final List<String> links = new ArrayList<>();
161 final SimpleHttpRequest getRoot1 = SimpleRequestBuilder.get()
162 .setHttpHost(target)
163 .setPath("/")
164 .build();
165 final Future<SimpleHttpResponse> future1 = client.execute(getRoot1, context, null);
166 try {
167 final SimpleHttpResponse response = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
168 final int code = response.getCode();
169 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
170 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
171 logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus);
172 } else {
173 logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")");
174 }
175 for (final Header header: response.getHeaders("Link")) {
176 final Matcher matcher = linkPattern.matcher(header.getValue());
177 if (matcher.matches()) {
178 links.add(matcher.group(1));
179 }
180 }
181 } catch (final ExecutionException ex) {
182 final Throwable cause = ex.getCause();
183 logResult(TestResult.NOK, getRoot1, "(" + cause.getMessage() + ")");
184 } catch (final TimeoutException ex) {
185 logResult(TestResult.NOK, getRoot1, "(time out)");
186 }
187 for (final String link: links) {
188 final SimpleHttpRequest getLink = SimpleRequestBuilder.get()
189 .setHttpHost(target)
190 .setPath(link)
191 .build();
192 final Future<SimpleHttpResponse> linkFuture = client.execute(getLink, context, null);
193 try {
194 final SimpleHttpResponse response = linkFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
195 final int code = response.getCode();
196 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
197 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
198 logResult(TestResult.OK, getLink, "200, " + cacheResponseStatus);
199 } else {
200 logResult(TestResult.NOK, getLink, "(status " + code + ", " + cacheResponseStatus + ")");
201 }
202 } catch (final ExecutionException ex) {
203 final Throwable cause = ex.getCause();
204 logResult(TestResult.NOK, getLink, "(" + cause.getMessage() + ")");
205 } catch (final TimeoutException ex) {
206 logResult(TestResult.NOK, getLink, "(time out)");
207 }
208 }
209
210 final SimpleHttpRequest getRoot2 = SimpleRequestBuilder.get()
211 .setHttpHost(target)
212 .setPath("/")
213 .build();
214 final Future<SimpleHttpResponse> future2 = client.execute(getRoot2, context, null);
215 try {
216 final SimpleHttpResponse response = future2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
217 final int code = response.getCode();
218 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
219 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
220 logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus);
221 } else {
222 logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")");
223 }
224 } catch (final ExecutionException ex) {
225 final Throwable cause = ex.getCause();
226 logResult(TestResult.NOK, getRoot2, "(" + cause.getMessage() + ")");
227 } catch (final TimeoutException ex) {
228 logResult(TestResult.NOK, getRoot2, "(time out)");
229 }
230 for (final String link: links) {
231 final SimpleHttpRequest getLink = SimpleRequestBuilder.get()
232 .setHttpHost(target)
233 .setPath(link)
234 .build();
235 final Future<SimpleHttpResponse> linkFuture = client.execute(getLink, context, null);
236 try {
237 final SimpleHttpResponse response = linkFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
238 final int code = response.getCode();
239 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
240 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
241 logResult(TestResult.OK, getLink, "200, " + cacheResponseStatus);
242 } else {
243 logResult(TestResult.NOK, getLink, "(status " + code + ", " + cacheResponseStatus + ")");
244 }
245 } catch (final ExecutionException ex) {
246 final Throwable cause = ex.getCause();
247 logResult(TestResult.NOK, getLink, "(" + cause.getMessage() + ")");
248 } catch (final TimeoutException ex) {
249 logResult(TestResult.NOK, getLink, "(time out)");
250 }
251 }
252 }
253 }
254
255 }