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.http.impl.cache;
28
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32
33 import org.apache.hc.client5.http.cache.HttpCacheEntry;
34 import org.apache.hc.client5.http.classic.methods.HttpGet;
35 import org.apache.hc.core5.http.Header;
36 import org.apache.hc.core5.http.HttpHost;
37 import org.apache.hc.core5.http.HttpRequest;
38 import org.apache.hc.core5.http.message.BasicHeader;
39 import org.apache.hc.core5.http.message.BasicHeaderIterator;
40 import org.apache.hc.core5.http.message.BasicHttpRequest;
41 import org.junit.jupiter.api.Assertions;
42 import org.junit.jupiter.api.BeforeEach;
43 import org.junit.jupiter.api.Test;
44
45 @SuppressWarnings({"boxing","static-access"})
46 public class TestCacheKeyGenerator {
47
48 private static final BasicHttpRequest REQUEST_FULL_EPISODES = new BasicHttpRequest("GET",
49 "/full_episodes");
50 private static final BasicHttpRequest REQUEST_ROOT = new BasicHttpRequest("GET", "/");
51
52 private CacheKeyGenerator extractor;
53 private HttpHost defaultHost;
54 private HttpCacheEntry mockEntry;
55 private HttpRequest mockRequest;
56
57 @BeforeEach
58 public void setUp() throws Exception {
59 defaultHost = new HttpHost("foo.example.com");
60 mockEntry = mock(HttpCacheEntry.class);
61 mockRequest = mock(HttpRequest.class);
62 extractor = CacheKeyGenerator.INSTANCE;
63 }
64
65 @Test
66 public void testExtractsUriFromAbsoluteUriInRequest() {
67 final HttpHost host = new HttpHost("bar.example.com");
68 final HttpRequest req = new HttpGet("http://foo.example.com/");
69 Assertions.assertEquals("http://foo.example.com:80/", extractor.generateKey(host, req));
70 }
71
72 @Test
73 public void testGetURIWithDefaultPortAndScheme() {
74 Assertions.assertEquals("http://www.comcast.net:80/", extractor.generateKey(new HttpHost(
75 "www.comcast.net"), REQUEST_ROOT));
76
77 Assertions.assertEquals("http://www.fancast.com:80/full_episodes", extractor.generateKey(new HttpHost(
78 "www.fancast.com"), REQUEST_FULL_EPISODES));
79 }
80
81 @Test
82 public void testGetURIWithDifferentScheme() {
83 Assertions.assertEquals("https://www.comcast.net:443/", extractor.generateKey(
84 new HttpHost("https", "www.comcast.net", -1), REQUEST_ROOT));
85
86 Assertions.assertEquals("myhttp://www.fancast.com/full_episodes", extractor.generateKey(
87 new HttpHost("myhttp", "www.fancast.com", -1), REQUEST_FULL_EPISODES));
88 }
89
90 @Test
91 public void testGetURIWithDifferentPort() {
92 Assertions.assertEquals("http://www.comcast.net:8080/", extractor.generateKey(new HttpHost(
93 "www.comcast.net", 8080), REQUEST_ROOT));
94
95 Assertions.assertEquals("http://www.fancast.com:9999/full_episodes", extractor.generateKey(
96 new HttpHost("www.fancast.com", 9999), REQUEST_FULL_EPISODES));
97 }
98
99 @Test
100 public void testGetURIWithDifferentPortAndScheme() {
101 Assertions.assertEquals("https://www.comcast.net:8080/", extractor.generateKey(
102 new HttpHost("https", "www.comcast.net", 8080), REQUEST_ROOT));
103
104 Assertions.assertEquals("myhttp://www.fancast.com:9999/full_episodes", extractor.generateKey(
105 new HttpHost("myhttp", "www.fancast.com", 9999), REQUEST_FULL_EPISODES));
106 }
107
108 @Test
109 public void testGetURIWithQueryParameters() {
110 Assertions.assertEquals("http://www.comcast.net:80/?foo=bar", extractor.generateKey(
111 new HttpHost("http", "www.comcast.net", -1), new BasicHttpRequest("GET", "/?foo=bar")));
112 Assertions.assertEquals("http://www.fancast.com:80/full_episodes?foo=bar", extractor.generateKey(
113 new HttpHost("http", "www.fancast.com", -1), new BasicHttpRequest("GET",
114 "/full_episodes?foo=bar")));
115 }
116
117 @Test
118 public void testGetVariantURIWithNoVaryHeaderReturnsNormalURI() {
119 final String theURI = "theURI";
120 when(mockEntry.hasVariants()).thenReturn(false);
121 extractor = new CacheKeyGenerator() {
122 @Override
123 public String generateKey(final HttpHost h, final HttpRequest request) {
124 Assertions.assertSame(defaultHost, h);
125 Assertions.assertSame(mockRequest, request);
126 return theURI;
127 }
128 };
129
130 final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
131 verify(mockEntry).hasVariants();
132 Assertions.assertSame(theURI, result);
133 }
134
135 @Test
136 public void testGetVariantURIWithSingleValueVaryHeaderPrepends() {
137 final String theURI = "theURI";
138 final Header[] varyHeaders = { new BasicHeader("Vary", "Accept-Encoding") };
139 final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip") };
140
141 extractor = new CacheKeyGenerator() {
142 @Override
143 public String generateKey(final HttpHost h, final HttpRequest request) {
144 Assertions.assertSame(defaultHost, h);
145 Assertions.assertSame(mockRequest, request);
146 return theURI;
147 }
148 };
149 when(mockEntry.hasVariants()).thenReturn(true);
150 when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
151 when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
152
153 final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
154
155 verify(mockEntry).hasVariants();
156 verify(mockEntry).headerIterator("Vary");
157 verify(mockRequest).getHeaders("Accept-Encoding");
158 Assertions.assertEquals("{Accept-Encoding=gzip}" + theURI, result);
159 }
160
161 @Test
162 public void testGetVariantURIWithMissingRequestHeader() {
163 final String theURI = "theURI";
164 final Header[] noHeaders = new Header[0];
165 final Header[] varyHeaders = { new BasicHeader("Vary", "Accept-Encoding") };
166 extractor = new CacheKeyGenerator() {
167 @Override
168 public String generateKey(final HttpHost h, final HttpRequest request) {
169 Assertions.assertSame(defaultHost, h);
170 Assertions.assertSame(mockRequest, request);
171 return theURI;
172 }
173 };
174 when(mockEntry.hasVariants()).thenReturn(true);
175 when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
176 when(mockRequest.getHeaders("Accept-Encoding"))
177 .thenReturn(noHeaders);
178
179 final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
180
181 verify(mockEntry).hasVariants();
182 verify(mockEntry).headerIterator("Vary");
183 verify(mockRequest).getHeaders("Accept-Encoding");
184 Assertions.assertEquals("{Accept-Encoding=}" + theURI, result);
185 }
186
187 @Test
188 public void testGetVariantURIAlphabetizesWithMultipleVaryingHeaders() {
189 final String theURI = "theURI";
190 final Header[] varyHeaders = { new BasicHeader("Vary", "User-Agent, Accept-Encoding") };
191 final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip") };
192 final Header[] uaHeaders = { new BasicHeader("User-Agent", "browser") };
193 extractor = new CacheKeyGenerator() {
194 @Override
195 public String generateKey(final HttpHost h, final HttpRequest request) {
196 Assertions.assertSame(defaultHost, h);
197 Assertions.assertSame(mockRequest, request);
198 return theURI;
199 }
200 };
201 when(mockEntry.hasVariants()).thenReturn(true);
202 when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
203 when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
204 when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
205
206 final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
207
208 verify(mockEntry).hasVariants();
209 verify(mockEntry).headerIterator("Vary");
210 verify(mockRequest).getHeaders("Accept-Encoding");
211 verify(mockRequest).getHeaders("User-Agent");
212 Assertions.assertEquals("{Accept-Encoding=gzip&User-Agent=browser}" + theURI, result);
213 }
214
215 @Test
216 public void testGetVariantURIHandlesMultipleVaryHeaders() {
217 final String theURI = "theURI";
218 final Header[] varyHeaders = { new BasicHeader("Vary", "User-Agent"),
219 new BasicHeader("Vary", "Accept-Encoding") };
220 final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip") };
221 final Header[] uaHeaders = { new BasicHeader("User-Agent", "browser") };
222 extractor = new CacheKeyGenerator() {
223 @Override
224 public String generateKey(final HttpHost h, final HttpRequest request) {
225 Assertions.assertSame(defaultHost, h);
226 Assertions.assertSame(mockRequest, request);
227 return theURI;
228 }
229 };
230 when(mockEntry.hasVariants()).thenReturn(true);
231 when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
232 when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
233 when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
234
235 final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
236
237 verify(mockEntry).hasVariants();
238 verify(mockEntry).headerIterator("Vary");
239 verify(mockRequest).getHeaders("Accept-Encoding");
240 verify(mockRequest).getHeaders("User-Agent");
241 Assertions.assertEquals("{Accept-Encoding=gzip&User-Agent=browser}" + theURI, result);
242 }
243
244 @Test
245 public void testGetVariantURIHandlesMultipleLineRequestHeaders() {
246 final String theURI = "theURI";
247 final Header[] varyHeaders = { new BasicHeader("Vary", "User-Agent, Accept-Encoding") };
248 final Header[] encHeaders = { new BasicHeader("Accept-Encoding", "gzip"),
249 new BasicHeader("Accept-Encoding", "deflate") };
250 final Header[] uaHeaders = { new BasicHeader("User-Agent", "browser") };
251 extractor = new CacheKeyGenerator() {
252 @Override
253 public String generateKey(final HttpHost h, final HttpRequest request) {
254 Assertions.assertSame(defaultHost, h);
255 Assertions.assertSame(mockRequest, request);
256 return theURI;
257 }
258 };
259 when(mockEntry.hasVariants()).thenReturn(true);
260 when(mockEntry.headerIterator("Vary")).thenReturn(new BasicHeaderIterator(varyHeaders, "Vary"));
261 when(mockRequest.getHeaders("Accept-Encoding")).thenReturn(encHeaders);
262 when(mockRequest.getHeaders("User-Agent")).thenReturn(uaHeaders);
263
264 final String result = extractor.generateKey(defaultHost, mockRequest, mockEntry);
265
266 verify(mockEntry).hasVariants();
267 verify(mockEntry).headerIterator("Vary");
268 verify(mockRequest).getHeaders("Accept-Encoding");
269 verify(mockRequest).getHeaders("User-Agent");
270 Assertions.assertEquals("{Accept-Encoding=gzip%2C+deflate&User-Agent=browser}" + theURI, result);
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287 @Test
288 public void testEmptyPortEquivalentToDefaultPortForHttp() {
289 final HttpHost host1 = new HttpHost("foo.example.com:");
290 final HttpHost host2 = new HttpHost("foo.example.com:80");
291 final HttpRequest req = new BasicHttpRequest("GET", "/");
292 Assertions.assertEquals(extractor.generateKey(host1, req), extractor.generateKey(host2, req));
293 }
294
295 @Test
296 public void testEmptyPortEquivalentToDefaultPortForHttps() {
297 final HttpHost host1 = new HttpHost("https", "foo.example.com", -1);
298 final HttpHost host2 = new HttpHost("https", "foo.example.com", 443);
299 final HttpRequest req = new BasicHttpRequest("GET", "/");
300 final String uri1 = extractor.generateKey(host1, req);
301 final String uri2 = extractor.generateKey(host2, req);
302 Assertions.assertEquals(uri1, uri2);
303 }
304
305 @Test
306 public void testEmptyPortEquivalentToDefaultPortForHttpsAbsoluteURI() {
307 final HttpHost host = new HttpHost("https", "foo.example.com", -1);
308 final HttpGet get1 = new HttpGet("https://bar.example.com:/");
309 final HttpGet get2 = new HttpGet("https://bar.example.com:443/");
310 final String uri1 = extractor.generateKey(host, get1);
311 final String uri2 = extractor.generateKey(host, get2);
312 Assertions.assertEquals(uri1, uri2);
313 }
314
315 @Test
316 public void testNotProvidedPortEquivalentToDefaultPortForHttpsAbsoluteURI() {
317 final HttpHost host = new HttpHost("https", "foo.example.com", -1);
318 final HttpGet get1 = new HttpGet("https://bar.example.com/");
319 final HttpGet get2 = new HttpGet("https://bar.example.com:443/");
320 final String uri1 = extractor.generateKey(host, get1);
321 final String uri2 = extractor.generateKey(host, get2);
322 Assertions.assertEquals(uri1, uri2);
323 }
324
325 @Test
326 public void testNotProvidedPortEquivalentToDefaultPortForHttp() {
327 final HttpHost host1 = new HttpHost("foo.example.com");
328 final HttpHost host2 = new HttpHost("foo.example.com:80");
329 final HttpRequest req = new BasicHttpRequest("GET", "/");
330 Assertions.assertEquals(extractor.generateKey(host1, req), extractor.generateKey(host2, req));
331 }
332
333 @Test
334 public void testHostNameComparisonsAreCaseInsensitive() {
335 final HttpHost host1 = new HttpHost("foo.example.com");
336 final HttpHost host2 = new HttpHost("FOO.EXAMPLE.COM");
337 final HttpRequest req = new BasicHttpRequest("GET", "/");
338 Assertions.assertEquals(extractor.generateKey(host1, req), extractor.generateKey(host2, req));
339 }
340
341 @Test
342 public void testSchemeNameComparisonsAreCaseInsensitive() {
343 final HttpHost host1 = new HttpHost("http", "foo.example.com", -1);
344 final HttpHost host2 = new HttpHost("HTTP", "foo.example.com", -1);
345 final HttpRequest req = new BasicHttpRequest("GET", "/");
346 Assertions.assertEquals(extractor.generateKey(host1, req), extractor.generateKey(host2, req));
347 }
348
349 @Test
350 public void testEmptyAbsPathIsEquivalentToSlash() {
351 final HttpHost host = new HttpHost("foo.example.com");
352 final HttpRequest req1 = new BasicHttpRequest("GET", "/");
353 final HttpRequest req2 = new HttpGet("http://foo.example.com");
354 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
355 }
356
357 @Test
358 public void testExtraDotSegmentsAreIgnored() {
359 final HttpHost host = new HttpHost("foo.example.com");
360 final HttpRequest req1 = new BasicHttpRequest("GET", "/");
361 final HttpRequest req2 = new HttpGet("http://foo.example.com/./");
362 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
363 }
364
365 @Test
366 public void testExtraDotDotSegmentsAreIgnored() {
367 final HttpHost host = new HttpHost("foo.example.com");
368 final HttpRequest req1 = new BasicHttpRequest("GET", "/");
369 final HttpRequest req2 = new HttpGet("http://foo.example.com/.././../");
370 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
371 }
372
373 @Test
374 public void testIntermidateDotDotSegementsAreEquivalent() {
375 final HttpHost host = new HttpHost("foo.example.com");
376 final HttpRequest req1 = new BasicHttpRequest("GET", "/home.html");
377 final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/../home.html");
378 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
379 }
380
381 @Test
382 public void testIntermidateEncodedDotDotSegementsAreEquivalent() {
383 final HttpHost host = new HttpHost("foo.example.com");
384 final HttpRequest req1 = new BasicHttpRequest("GET", "/home.html");
385 final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/../home.html");
386 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
387 }
388
389 @Test
390 public void testIntermidateDotSegementsAreEquivalent() {
391 final HttpHost host = new HttpHost("foo.example.com");
392 final HttpRequest req1 = new BasicHttpRequest("GET", "/~smith/home.html");
393 final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/./home.html");
394 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
395 }
396
397 @Test
398 public void testEquivalentPathEncodingsAreEquivalent() {
399 final HttpHost host = new HttpHost("foo.example.com");
400 final HttpRequest req1 = new BasicHttpRequest("GET", "/~smith/home.html");
401 final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/home.html");
402 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
403 }
404
405 @Test
406 public void testEquivalentExtraPathEncodingsAreEquivalent() {
407 final HttpHost host = new HttpHost("foo.example.com");
408 final HttpRequest req1 = new BasicHttpRequest("GET", "/~smith/home.html");
409 final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/home.html");
410 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
411 }
412
413 @Test
414 public void testEquivalentExtraPathEncodingsWithPercentAreEquivalent() {
415 final HttpHost host = new HttpHost("foo.example.com");
416 final HttpRequest req1 = new BasicHttpRequest("GET", "/~smith/home%20folder.html");
417 final HttpRequest req2 = new BasicHttpRequest("GET", "/%7Esmith/home%20folder.html");
418 Assertions.assertEquals(extractor.generateKey(host, req1), extractor.generateKey(host, req2));
419 }
420 }