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 java.time.Instant;
30 import java.util.Arrays;
31 import java.util.List;
32
33 import org.apache.hc.client5.http.cache.HttpCacheEntry;
34 import org.apache.hc.client5.http.utils.DateUtils;
35 import org.apache.hc.core5.http.Header;
36 import org.apache.hc.core5.http.HttpHeaders;
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.BasicHttpRequest;
40 import org.apache.hc.core5.http.support.BasicRequestBuilder;
41 import org.junit.jupiter.api.Assertions;
42 import org.junit.jupiter.api.BeforeEach;
43 import org.junit.jupiter.api.Test;
44
45 public class TestConditionalRequestBuilder {
46
47 private ConditionalRequestBuilder<HttpRequest> impl;
48 private HttpRequest request;
49
50 @BeforeEach
51 public void setUp() throws Exception {
52 impl = new ConditionalRequestBuilder<>(request -> BasicRequestBuilder.copy(request).build());
53 request = new BasicHttpRequest("GET", "/");
54 }
55
56 @Test
57 public void testBuildConditionalRequestWithLastModified() {
58 final String theMethod = "GET";
59 final String theUri = "/theuri";
60 final String lastModified = "this is my last modified date";
61
62 final HttpRequest basicRequest = new BasicHttpRequest(theMethod, theUri);
63 basicRequest.addHeader("Accept-Encoding", "gzip");
64
65 final Header[] headers = new Header[] {
66 new BasicHeader("Date", DateUtils.formatStandardDate(Instant.now())),
67 new BasicHeader("Last-Modified", lastModified) };
68
69 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
70 final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
71 final HttpRequest newRequest = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
72
73 Assertions.assertEquals(theMethod, newRequest.getMethod());
74 Assertions.assertEquals(theUri, newRequest.getRequestUri());
75 Assertions.assertEquals(2, newRequest.getHeaders().length);
76
77 Assertions.assertEquals("Accept-Encoding", newRequest.getHeaders()[0].getName());
78 Assertions.assertEquals("gzip", newRequest.getHeaders()[0].getValue());
79
80 Assertions.assertEquals("If-Modified-Since", newRequest.getHeaders()[1].getName());
81 Assertions.assertEquals(lastModified, newRequest.getHeaders()[1].getValue());
82 }
83
84 @Test
85 public void testConditionalRequestForEntryWithLastModifiedAndEtagIncludesBothAsValidators()
86 throws Exception {
87 final Instant now = Instant.now();
88 final Instant tenSecondsAgo = now.minusSeconds(10);
89 final Instant twentySecondsAgo = now.plusSeconds(20);
90 final String lmDate = DateUtils.formatStandardDate(twentySecondsAgo);
91 final String etag = "\"etag\"";
92 final Header[] headers = {
93 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
94 new BasicHeader("Last-Modified", lmDate),
95 new BasicHeader("ETag", etag)
96 };
97 final HttpRequest basicRequest = new BasicHttpRequest("GET", "/");
98 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
99 final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
100 final HttpRequest result = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
101 Assertions.assertEquals(lmDate,
102 result.getFirstHeader("If-Modified-Since").getValue());
103 Assertions.assertEquals(etag,
104 result.getFirstHeader("If-None-Match").getValue());
105 }
106
107 @Test
108 public void testBuildConditionalRequestWithETag() {
109 final String theMethod = "GET";
110 final String theUri = "/theuri";
111 final String theETag = "this is my eTag";
112
113 final HttpRequest basicRequest = new BasicHttpRequest(theMethod, theUri);
114 basicRequest.addHeader("Accept-Encoding", "gzip");
115
116 final Header[] headers = new Header[] {
117 new BasicHeader("Date", DateUtils.formatStandardDate(Instant.now())),
118 new BasicHeader("Last-Modified", DateUtils.formatStandardDate(Instant.now())),
119 new BasicHeader("ETag", theETag) };
120
121 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
122
123 final ResponseCacheControl cacheControl = ResponseCacheControl.builder().build();
124 final HttpRequest newRequest = impl.buildConditionalRequest(cacheControl, basicRequest, cacheEntry);
125
126 Assertions.assertEquals(theMethod, newRequest.getMethod());
127 Assertions.assertEquals(theUri, newRequest.getRequestUri());
128
129 Assertions.assertEquals(3, newRequest.getHeaders().length);
130
131 Assertions.assertEquals("Accept-Encoding", newRequest.getHeaders()[0].getName());
132 Assertions.assertEquals("gzip", newRequest.getHeaders()[0].getValue());
133
134 Assertions.assertEquals("If-None-Match", newRequest.getHeaders()[1].getName());
135 Assertions.assertEquals(theETag, newRequest.getHeaders()[1].getValue());
136 }
137
138 @Test
139 public void testCacheEntryWithMustRevalidateDoesEndToEndRevalidation() throws Exception {
140 final HttpRequest basicRequest = new BasicHttpRequest("GET","/");
141 final Instant now = Instant.now();
142 final Instant elevenSecondsAgo = now.minusSeconds(11);
143 final Instant tenSecondsAgo = now.minusSeconds(10);
144 final Instant nineSecondsAgo = now.plusSeconds(9);
145
146 final Header[] cacheEntryHeaders = new Header[] {
147 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
148 new BasicHeader("ETag", "\"etag\"")
149 };
150 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
151
152 final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
153 .setMaxAge(5)
154 .setMustRevalidate(true)
155 .build();
156 final HttpRequest result = impl.buildConditionalRequest(responseCacheControl, basicRequest, cacheEntry);
157
158 final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
159 Assertions.assertEquals(0, requestCacheControl.getMaxAge());
160 }
161
162 @Test
163 public void testCacheEntryWithProxyRevalidateDoesEndToEndRevalidation() throws Exception {
164 final HttpRequest basicRequest = new BasicHttpRequest("GET", "/");
165 final Instant now = Instant.now();
166 final Instant elevenSecondsAgo = now.minusSeconds(11);
167 final Instant tenSecondsAgo = now.minusSeconds(10);
168 final Instant nineSecondsAgo = now.plusSeconds(9);
169
170 final Header[] cacheEntryHeaders = new Header[] {
171 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
172 new BasicHeader("ETag", "\"etag\"")
173 };
174 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
175
176 final ResponseCacheControl responseCacheControl = ResponseCacheControl.builder()
177 .setMaxAge(5)
178 .setProxyRevalidate(true)
179 .build();
180 final HttpRequest result = impl.buildConditionalRequest(responseCacheControl, basicRequest, cacheEntry);
181
182 final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
183 Assertions.assertEquals(0, requestCacheControl.getMaxAge());
184 }
185
186 @Test
187 public void testBuildUnconditionalRequestUsesGETMethod()
188 throws Exception {
189 final HttpRequest result = impl.buildUnconditionalRequest(request);
190 Assertions.assertEquals("GET", result.getMethod());
191 }
192
193 @Test
194 public void testBuildUnconditionalRequestUsesRequestUri()
195 throws Exception {
196 final String uri = "/theURI";
197 request = new BasicHttpRequest("GET", uri);
198 final HttpRequest result = impl.buildUnconditionalRequest(request);
199 Assertions.assertEquals(uri, result.getRequestUri());
200 }
201
202 @Test
203 public void testBuildUnconditionalRequestAddsCacheControlNoCache()
204 throws Exception {
205 final HttpRequest result = impl.buildUnconditionalRequest(request);
206 final RequestCacheControl requestCacheControl = CacheControlHeaderParser.INSTANCE.parse(result);
207 Assertions.assertTrue(requestCacheControl.isNoCache());
208 }
209
210 @Test
211 public void testBuildUnconditionalRequestDoesNotUseIfRange()
212 throws Exception {
213 request.addHeader("If-Range","\"etag\"");
214 final HttpRequest result = impl.buildUnconditionalRequest(request);
215 Assertions.assertNull(result.getFirstHeader("If-Range"));
216 }
217
218 @Test
219 public void testBuildUnconditionalRequestDoesNotUseIfMatch()
220 throws Exception {
221 request.addHeader("If-Match","\"etag\"");
222 final HttpRequest result = impl.buildUnconditionalRequest(request);
223 Assertions.assertNull(result.getFirstHeader("If-Match"));
224 }
225
226 @Test
227 public void testBuildUnconditionalRequestDoesNotUseIfNoneMatch()
228 throws Exception {
229 request.addHeader("If-None-Match","\"etag\"");
230 final HttpRequest result = impl.buildUnconditionalRequest(request);
231 Assertions.assertNull(result.getFirstHeader("If-None-Match"));
232 }
233
234 @Test
235 public void testBuildUnconditionalRequestDoesNotUseIfUnmodifiedSince()
236 throws Exception {
237 request.addHeader("If-Unmodified-Since", DateUtils.formatStandardDate(Instant.now()));
238 final HttpRequest result = impl.buildUnconditionalRequest(request);
239 Assertions.assertNull(result.getFirstHeader("If-Unmodified-Since"));
240 }
241
242 @Test
243 public void testBuildUnconditionalRequestDoesNotUseIfModifiedSince()
244 throws Exception {
245 request.addHeader("If-Modified-Since", DateUtils.formatStandardDate(Instant.now()));
246 final HttpRequest result = impl.buildUnconditionalRequest(request);
247 Assertions.assertNull(result.getFirstHeader("If-Modified-Since"));
248 }
249
250 @Test
251 public void testBuildUnconditionalRequestCarriesOtherRequestHeaders()
252 throws Exception {
253 request.addHeader("User-Agent","MyBrowser/1.0");
254 final HttpRequest result = impl.buildUnconditionalRequest(request);
255 Assertions.assertEquals("MyBrowser/1.0",
256 result.getFirstHeader("User-Agent").getValue());
257 }
258
259 @Test
260 public void testBuildConditionalRequestFromVariants() throws Exception {
261 final String etag1 = "\"123\"";
262 final String etag2 = "\"456\"";
263 final String etag3 = "\"789\"";
264
265 final List<String> variantEntries = Arrays.asList(etag1, etag2, etag3);
266
267 final HttpRequest conditional = impl.buildConditionalRequestFromVariants(request, variantEntries);
268
269
270 String ifNoneMatch = conditional.getFirstHeader(HttpHeaders.IF_NONE_MATCH).getValue();
271 Assertions.assertTrue(ifNoneMatch.contains(etag1));
272 Assertions.assertTrue(ifNoneMatch.contains(etag2));
273 Assertions.assertTrue(ifNoneMatch.contains(etag3));
274 ifNoneMatch = ifNoneMatch.replace(etag1, "");
275 ifNoneMatch = ifNoneMatch.replace(etag2, "");
276 ifNoneMatch = ifNoneMatch.replace(etag3, "");
277 ifNoneMatch = ifNoneMatch.replace(",","");
278 ifNoneMatch = ifNoneMatch.replace(" ", "");
279 Assertions.assertEquals(ifNoneMatch, "");
280 }
281
282 }