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.SimpleHttpRequests;
42 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
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 = SimpleHttpRequests.options(target, "*");
135 final Future<SimpleHttpResponse> future = client.execute(options, context, null);
136 try {
137 final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
138 final int code = response.getCode();
139 if (code == HttpStatus.SC_OK) {
140 logResult(TestResult.OK, options, Objects.toString(response.getFirstHeader("server")));
141 } else {
142 logResult(TestResult.NOK, options, "(status " + code + ")");
143 }
144 } catch (final ExecutionException ex) {
145 final Throwable cause = ex.getCause();
146 logResult(TestResult.NOK, options, "(" + cause.getMessage() + ")");
147 } catch (final TimeoutException ex) {
148 logResult(TestResult.NOK, options, "(time out)");
149 }
150 }
151
152 {
153 connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
154 final HttpCacheContext context = HttpCacheContext.create();
155
156 final Pattern linkPattern = Pattern.compile("^<(.*)>;rel=preload$");
157 final List<String> links = new ArrayList<>();
158 final SimpleHttpRequest getRoot1 = SimpleHttpRequests.get(target, "/");
159 final Future<SimpleHttpResponse> future1 = client.execute(getRoot1, context, null);
160 try {
161 final SimpleHttpResponse response = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
162 final int code = response.getCode();
163 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
164 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
165 logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus);
166 } else {
167 logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")");
168 }
169 for (final Header header: response.getHeaders("Link")) {
170 final Matcher matcher = linkPattern.matcher(header.getValue());
171 if (matcher.matches()) {
172 links.add(matcher.group(1));
173 }
174 }
175 } catch (final ExecutionException ex) {
176 final Throwable cause = ex.getCause();
177 logResult(TestResult.NOK, getRoot1, "(" + cause.getMessage() + ")");
178 } catch (final TimeoutException ex) {
179 logResult(TestResult.NOK, getRoot1, "(time out)");
180 }
181 for (final String link: links) {
182 final SimpleHttpRequest getLink = SimpleHttpRequests.get(target, link);
183 final Future<SimpleHttpResponse> linkFuture = client.execute(getLink, context, null);
184 try {
185 final SimpleHttpResponse response = linkFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
186 final int code = response.getCode();
187 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
188 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
189 logResult(TestResult.OK, getLink, "200, " + cacheResponseStatus);
190 } else {
191 logResult(TestResult.NOK, getLink, "(status " + code + ", " + cacheResponseStatus + ")");
192 }
193 } catch (final ExecutionException ex) {
194 final Throwable cause = ex.getCause();
195 logResult(TestResult.NOK, getLink, "(" + cause.getMessage() + ")");
196 } catch (final TimeoutException ex) {
197 logResult(TestResult.NOK, getLink, "(time out)");
198 }
199 }
200
201 final SimpleHttpRequest getRoot2 = SimpleHttpRequests.get(target, "/");
202 final Future<SimpleHttpResponse> future2 = client.execute(getRoot2, context, null);
203 try {
204 final SimpleHttpResponse response = future2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
205 final int code = response.getCode();
206 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
207 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
208 logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus);
209 } else {
210 logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")");
211 }
212 } catch (final ExecutionException ex) {
213 final Throwable cause = ex.getCause();
214 logResult(TestResult.NOK, getRoot2, "(" + cause.getMessage() + ")");
215 } catch (final TimeoutException ex) {
216 logResult(TestResult.NOK, getRoot2, "(time out)");
217 }
218 for (final String link: links) {
219 final SimpleHttpRequest getLink = SimpleHttpRequests.get(target, link);
220 final Future<SimpleHttpResponse> linkFuture = client.execute(getLink, context, null);
221 try {
222 final SimpleHttpResponse response = linkFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
223 final int code = response.getCode();
224 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
225 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
226 logResult(TestResult.OK, getLink, "200, " + cacheResponseStatus);
227 } else {
228 logResult(TestResult.NOK, getLink, "(status " + code + ", " + cacheResponseStatus + ")");
229 }
230 } catch (final ExecutionException ex) {
231 final Throwable cause = ex.getCause();
232 logResult(TestResult.NOK, getLink, "(" + cause.getMessage() + ")");
233 } catch (final TimeoutException ex) {
234 logResult(TestResult.NOK, getLink, "(time out)");
235 }
236 }
237 }
238 }
239
240 }