View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
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.regex.Matcher;
33  import java.util.regex.Pattern;
34  
35  import javax.net.ssl.SSLContext;
36  
37  import org.apache.hc.client5.http.cache.CacheResponseStatus;
38  import org.apache.hc.client5.http.cache.HttpCacheContext;
39  import org.apache.hc.client5.http.classic.methods.HttpGet;
40  import org.apache.hc.client5.http.classic.methods.HttpOptions;
41  import org.apache.hc.client5.http.impl.cache.CacheConfig;
42  import org.apache.hc.client5.http.impl.cache.CachingHttpClients;
43  import org.apache.hc.client5.http.impl.cache.HeapResourceFactory;
44  import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
45  import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
46  import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
47  import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
48  import org.apache.hc.core5.http.ClassicHttpResponse;
49  import org.apache.hc.core5.http.Header;
50  import org.apache.hc.core5.http.HttpHost;
51  import org.apache.hc.core5.http.HttpRequest;
52  import org.apache.hc.core5.http.HttpStatus;
53  import org.apache.hc.core5.http.io.entity.EntityUtils;
54  import org.apache.hc.core5.ssl.SSLContexts;
55  import org.apache.hc.core5.util.TextUtils;
56  import org.apache.hc.core5.util.TimeValue;
57  
58  public class CachingHttpClientCompatibilityTest {
59  
60      public static void main(final String... args) throws Exception {
61          final CachingHttpClientCompatibilityTestlientCompatibilityTest.html#CachingHttpClientCompatibilityTest">CachingHttpClientCompatibilityTest[] tests = new CachingHttpClientCompatibilityTest[] {
62                  new CachingHttpClientCompatibilityTest(
63                          new HttpHost("http", "localhost", 8080))
64          };
65          for (final CachingHttpClientCompatibilityTest test: tests) {
66              try {
67                  test.execute();
68              } finally {
69                  test.shutdown();
70              }
71          }
72      }
73  
74      private final HttpHost target;
75      private final PoolingHttpClientConnectionManager connManager;
76      private final CloseableHttpClient client;
77  
78      CachingHttpClientCompatibilityTest(final HttpHost target) throws Exception {
79          this.target = target;
80          final SSLContext sslContext = SSLContexts.custom()
81                  .loadTrustMaterial(getClass().getResource("/test-ca.keystore"), "nopassword".toCharArray()).build();
82          this.connManager = PoolingHttpClientConnectionManagerBuilder.create()
83                  .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext))
84                  .build();
85          this.client = CachingHttpClients.custom()
86                  .setCacheConfig(CacheConfig.custom()
87                          .setMaxObjectSize(20480)
88                          .build())
89                  .setResourceFactory(HeapResourceFactory.INSTANCE)
90                  .setConnectionManager(this.connManager)
91                  .build();
92      }
93  
94      void shutdown() throws Exception {
95          client.close();
96      }
97  
98      enum TestResult {OK, NOK}
99  
100     private void logResult(final TestResult result, final HttpRequest request, final String message) {
101         final StringBuilder buf = new StringBuilder();
102         buf.append(result);
103         if (buf.length() == 2) {
104             buf.append(" ");
105         }
106         buf.append(": ").append(target);
107         buf.append(": ");
108         buf.append(request.getMethod()).append(" ").append(request.getRequestUri());
109         if (message != null && !TextUtils.isBlank(message)) {
110             buf.append(" -> ").append(message);
111         }
112         System.out.println(buf);
113     }
114 
115     void execute() {
116 
117         // Initial ping
118         {
119             final HttpCacheContext context = HttpCacheContext.create();
120             final HttpOptions options = new HttpOptions("*");
121             try (final ClassicHttpResponse response = client.execute(target, options, context)) {
122                 final int code = response.getCode();
123                 EntityUtils.consume(response.getEntity());
124                 if (code == HttpStatus.SC_OK) {
125                     logResult(TestResult.OK, options, Objects.toString(response.getFirstHeader("server")));
126                 } else {
127                     logResult(TestResult.NOK, options, "(status " + code + ")");
128                 }
129             } catch (final Exception ex) {
130                 logResult(TestResult.NOK, options, "(" + ex.getMessage() + ")");
131             }
132         }
133         // GET with links
134         {
135             connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
136             final HttpCacheContext context = HttpCacheContext.create();
137             final Pattern linkPattern = Pattern.compile("^<(.*)>;rel=preload$");
138             final List<String> links = new ArrayList<>();
139             final HttpGet getRoot1 = new HttpGet("/");
140             try (ClassicHttpResponse response = client.execute(target, getRoot1, context)) {
141                 final int code = response.getCode();
142                 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
143                 EntityUtils.consume(response.getEntity());
144                 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
145                     logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus);
146                 } else {
147                     logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")");
148                 }
149                 for (final Header header: response.getHeaders("Link")) {
150                     final Matcher matcher = linkPattern.matcher(header.getValue());
151                     if (matcher.matches()) {
152                         links.add(matcher.group(1));
153                     }
154                 }
155             } catch (final Exception ex) {
156                 logResult(TestResult.NOK, getRoot1, "(" + ex.getMessage() + ")");
157             }
158 
159             for (final String link: links) {
160                 final HttpGet getLink = new HttpGet(link);
161                 try (ClassicHttpResponse response = client.execute(target, getLink, context)) {
162                     final int code = response.getCode();
163                     final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
164                     EntityUtils.consume(response.getEntity());
165                     if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
166                         logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus);
167                     } else {
168                         logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")");
169                     }
170                 } catch (final Exception ex) {
171                     logResult(TestResult.NOK, getLink, "(" + ex.getMessage() + ")");
172                 }
173             }
174             final HttpGet getRoot2 = new HttpGet("/");
175             try (ClassicHttpResponse response = client.execute(target, getRoot2, context)) {
176                 final int code = response.getCode();
177                 final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
178                 EntityUtils.consume(response.getEntity());
179                 if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
180                     logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus);
181                 } else {
182                     logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")");
183                 }
184             } catch (final Exception ex) {
185                 logResult(TestResult.NOK, getRoot2, "(" + ex.getMessage() + ")");
186             }
187             for (final String link: links) {
188                 final HttpGet getLink = new HttpGet(link);
189                 try (ClassicHttpResponse response = client.execute(target, getLink, context)) {
190                     final int code = response.getCode();
191                     final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
192                     EntityUtils.consume(response.getEntity());
193                     if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
194                         logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus);
195                     } else {
196                         logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")");
197                     }
198                 } catch (final Exception ex) {
199                     logResult(TestResult.NOK, getLink, "(" + ex.getMessage() + ")");
200                 }
201             }
202         }
203     }
204 
205 }