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.util.Date;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33
34 import org.apache.hc.client5.http.cache.HeaderConstants;
35 import org.apache.hc.client5.http.cache.HttpCacheEntry;
36 import org.apache.hc.client5.http.impl.RequestCopier;
37 import org.apache.hc.client5.http.utils.DateUtils;
38 import org.apache.hc.core5.http.Header;
39 import org.apache.hc.core5.http.HeaderElement;
40 import org.apache.hc.core5.http.HttpRequest;
41 import org.apache.hc.core5.http.message.BasicHeader;
42 import org.apache.hc.core5.http.message.BasicHttpRequest;
43 import org.apache.hc.core5.http.message.MessageSupport;
44 import org.junit.Assert;
45 import org.junit.Before;
46 import org.junit.Test;
47
48 public class TestConditionalRequestBuilder {
49
50 private ConditionalRequestBuilder<HttpRequest> impl;
51 private HttpRequest request;
52
53 @Before
54 public void setUp() throws Exception {
55 impl = new ConditionalRequestBuilder<>(RequestCopier.INSTANCE);
56 request = new BasicHttpRequest("GET", "/");
57 }
58
59 @Test
60 public void testBuildConditionalRequestWithLastModified() {
61 final String theMethod = "GET";
62 final String theUri = "/theuri";
63 final String lastModified = "this is my last modified date";
64
65 final HttpRequest basicRequest = new BasicHttpRequest(theMethod, theUri);
66 basicRequest.addHeader("Accept-Encoding", "gzip");
67 final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest);
68
69 final Header[] headers = new Header[] {
70 new BasicHeader("Date", DateUtils.formatDate(new Date())),
71 new BasicHeader("Last-Modified", lastModified) };
72
73 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
74 final HttpRequest newRequest = impl.buildConditionalRequest(requestWrapper, cacheEntry);
75
76 Assert.assertNotSame(basicRequest, newRequest);
77
78 Assert.assertEquals(theMethod, newRequest.getMethod());
79 Assert.assertEquals(theUri, newRequest.getRequestUri());
80 Assert.assertEquals(2, newRequest.getHeaders().length);
81
82 Assert.assertEquals("Accept-Encoding", newRequest.getHeaders()[0].getName());
83 Assert.assertEquals("gzip", newRequest.getHeaders()[0].getValue());
84
85 Assert.assertEquals("If-Modified-Since", newRequest.getHeaders()[1].getName());
86 Assert.assertEquals(lastModified, newRequest.getHeaders()[1].getValue());
87 }
88
89 @Test
90 public void testConditionalRequestForEntryWithLastModifiedAndEtagIncludesBothAsValidators()
91 throws Exception {
92 final Date now = new Date();
93 final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
94 final Date twentySecondsAgo = new Date(now.getTime() - 20 * 1000L);
95 final String lmDate = DateUtils.formatDate(twentySecondsAgo);
96 final String etag = "\"etag\"";
97 final Header[] headers = {
98 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
99 new BasicHeader("Last-Modified", lmDate),
100 new BasicHeader("ETag", etag)
101 };
102 final HttpRequest basicRequest = new BasicHttpRequest("GET", "/");
103 final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest);
104 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
105 final HttpRequest result = impl.buildConditionalRequest(requestWrapper, cacheEntry);
106 Assert.assertEquals(lmDate,
107 result.getFirstHeader("If-Modified-Since").getValue());
108 Assert.assertEquals(etag,
109 result.getFirstHeader("If-None-Match").getValue());
110 }
111
112 @Test
113 public void testBuildConditionalRequestWithETag() {
114 final String theMethod = "GET";
115 final String theUri = "/theuri";
116 final String theETag = "this is my eTag";
117
118 final HttpRequest basicRequest = new BasicHttpRequest(theMethod, theUri);
119 basicRequest.addHeader("Accept-Encoding", "gzip");
120 final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest);
121
122 final Header[] headers = new Header[] {
123 new BasicHeader("Date", DateUtils.formatDate(new Date())),
124 new BasicHeader("Last-Modified", DateUtils.formatDate(new Date())),
125 new BasicHeader("ETag", theETag) };
126
127 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(headers);
128
129 final HttpRequest newRequest = impl.buildConditionalRequest(requestWrapper, cacheEntry);
130
131 Assert.assertNotSame(basicRequest, newRequest);
132
133 Assert.assertEquals(theMethod, newRequest.getMethod());
134 Assert.assertEquals(theUri, newRequest.getRequestUri());
135
136 Assert.assertEquals(3, newRequest.getHeaders().length);
137
138 Assert.assertEquals("Accept-Encoding", newRequest.getHeaders()[0].getName());
139 Assert.assertEquals("gzip", newRequest.getHeaders()[0].getValue());
140
141 Assert.assertEquals("If-None-Match", newRequest.getHeaders()[1].getName());
142 Assert.assertEquals(theETag, newRequest.getHeaders()[1].getValue());
143 }
144
145 @Test
146 public void testCacheEntryWithMustRevalidateDoesEndToEndRevalidation() throws Exception {
147 final HttpRequest basicRequest = new BasicHttpRequest("GET","/");
148 final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest);
149 final Date now = new Date();
150 final Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L);
151 final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
152 final Date nineSecondsAgo = new Date(now.getTime() - 9 * 1000L);
153
154 final Header[] cacheEntryHeaders = new Header[] {
155 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
156 new BasicHeader("ETag", "\"etag\""),
157 new BasicHeader("Cache-Control","max-age=5, must-revalidate") };
158 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
159
160 final HttpRequest result = impl.buildConditionalRequest(requestWrapper, cacheEntry);
161
162 boolean foundMaxAge0 = false;
163
164 final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.CACHE_CONTROL);
165 while (it.hasNext()) {
166 final HeaderElement elt = it.next();
167 if ("max-age".equalsIgnoreCase(elt.getName()) && "0".equals(elt.getValue())) {
168 foundMaxAge0 = true;
169 }
170 }
171 Assert.assertTrue(foundMaxAge0);
172 }
173
174 @Test
175 public void testCacheEntryWithProxyRevalidateDoesEndToEndRevalidation() throws Exception {
176 final HttpRequest basicRequest = new BasicHttpRequest("GET", "/");
177 final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest);
178 final Date now = new Date();
179 final Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L);
180 final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
181 final Date nineSecondsAgo = new Date(now.getTime() - 9 * 1000L);
182
183 final Header[] cacheEntryHeaders = new Header[] {
184 new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
185 new BasicHeader("ETag", "\"etag\""),
186 new BasicHeader("Cache-Control","max-age=5, proxy-revalidate") };
187 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders);
188
189 final HttpRequest result = impl.buildConditionalRequest(requestWrapper, cacheEntry);
190
191 boolean foundMaxAge0 = false;
192 final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.CACHE_CONTROL);
193 while (it.hasNext()) {
194 final HeaderElement elt = it.next();
195 if ("max-age".equalsIgnoreCase(elt.getName()) && "0".equals(elt.getValue())) {
196 foundMaxAge0 = true;
197 }
198 }
199 Assert.assertTrue(foundMaxAge0);
200 }
201
202 @Test
203 public void testBuildUnconditionalRequestUsesGETMethod()
204 throws Exception {
205 final HttpRequest result = impl.buildUnconditionalRequest(request);
206 Assert.assertEquals("GET", result.getMethod());
207 }
208
209 @Test
210 public void testBuildUnconditionalRequestUsesRequestUri()
211 throws Exception {
212 final String uri = "/theURI";
213 request = new BasicHttpRequest("GET", uri);
214 final HttpRequest result = impl.buildUnconditionalRequest(request);
215 Assert.assertEquals(uri, result.getRequestUri());
216 }
217
218 @Test
219 public void testBuildUnconditionalRequestAddsCacheControlNoCache()
220 throws Exception {
221 final HttpRequest result = impl.buildUnconditionalRequest(request);
222 boolean ccNoCacheFound = false;
223 final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.CACHE_CONTROL);
224 while (it.hasNext()) {
225 final HeaderElement elt = it.next();
226 if ("no-cache".equals(elt.getName())) {
227 ccNoCacheFound = true;
228 }
229 }
230 Assert.assertTrue(ccNoCacheFound);
231 }
232
233 @Test
234 public void testBuildUnconditionalRequestAddsPragmaNoCache()
235 throws Exception {
236 final HttpRequest result = impl.buildUnconditionalRequest(request);
237 boolean ccNoCacheFound = false;
238 final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.PRAGMA);
239 while (it.hasNext()) {
240 final HeaderElement elt = it.next();
241 if ("no-cache".equals(elt.getName())) {
242 ccNoCacheFound = true;
243 }
244 }
245 Assert.assertTrue(ccNoCacheFound);
246 }
247
248 @Test
249 public void testBuildUnconditionalRequestDoesNotUseIfRange()
250 throws Exception {
251 request.addHeader("If-Range","\"etag\"");
252 final HttpRequest result = impl.buildUnconditionalRequest(request);
253 Assert.assertNull(result.getFirstHeader("If-Range"));
254 }
255
256 @Test
257 public void testBuildUnconditionalRequestDoesNotUseIfMatch()
258 throws Exception {
259 request.addHeader("If-Match","\"etag\"");
260 final HttpRequest result = impl.buildUnconditionalRequest(request);
261 Assert.assertNull(result.getFirstHeader("If-Match"));
262 }
263
264 @Test
265 public void testBuildUnconditionalRequestDoesNotUseIfNoneMatch()
266 throws Exception {
267 request.addHeader("If-None-Match","\"etag\"");
268 final HttpRequest result = impl.buildUnconditionalRequest(request);
269 Assert.assertNull(result.getFirstHeader("If-None-Match"));
270 }
271
272 @Test
273 public void testBuildUnconditionalRequestDoesNotUseIfUnmodifiedSince()
274 throws Exception {
275 request.addHeader("If-Unmodified-Since", DateUtils.formatDate(new Date()));
276 final HttpRequest result = impl.buildUnconditionalRequest(request);
277 Assert.assertNull(result.getFirstHeader("If-Unmodified-Since"));
278 }
279
280 @Test
281 public void testBuildUnconditionalRequestDoesNotUseIfModifiedSince()
282 throws Exception {
283 request.addHeader("If-Modified-Since", DateUtils.formatDate(new Date()));
284 final HttpRequest result = impl.buildUnconditionalRequest(request);
285 Assert.assertNull(result.getFirstHeader("If-Modified-Since"));
286 }
287
288 @Test
289 public void testBuildUnconditionalRequestCarriesOtherRequestHeaders()
290 throws Exception {
291 request.addHeader("User-Agent","MyBrowser/1.0");
292 final HttpRequest result = impl.buildUnconditionalRequest(request);
293 Assert.assertEquals("MyBrowser/1.0",
294 result.getFirstHeader("User-Agent").getValue());
295 }
296
297 @Test
298 public void testBuildConditionalRequestFromVariants() throws Exception {
299 final String etag1 = "\"123\"";
300 final String etag2 = "\"456\"";
301 final String etag3 = "\"789\"";
302
303 final Map<String,Variant> variantEntries = new HashMap<>();
304 variantEntries.put(etag1, new Variant("A", HttpTestUtils.makeCacheEntry(new Header[] { new BasicHeader("ETag", etag1) })));
305 variantEntries.put(etag2, new Variant("B", HttpTestUtils.makeCacheEntry(new Header[] { new BasicHeader("ETag", etag2) })));
306 variantEntries.put(etag3, new Variant("C", HttpTestUtils.makeCacheEntry(new Header[] { new BasicHeader("ETag", etag3) })));
307
308 final HttpRequest conditional = impl.buildConditionalRequestFromVariants(request, variantEntries);
309
310
311 String ifNoneMatch = conditional.getFirstHeader(HeaderConstants.IF_NONE_MATCH).getValue();
312 Assert.assertTrue(ifNoneMatch.contains(etag1));
313 Assert.assertTrue(ifNoneMatch.contains(etag2));
314 Assert.assertTrue(ifNoneMatch.contains(etag3));
315 ifNoneMatch = ifNoneMatch.replace(etag1, "");
316 ifNoneMatch = ifNoneMatch.replace(etag2, "");
317 ifNoneMatch = ifNoneMatch.replace(etag3, "");
318 ifNoneMatch = ifNoneMatch.replace(",","");
319 ifNoneMatch = ifNoneMatch.replace(" ", "");
320 Assert.assertEquals(ifNoneMatch, "");
321 }
322
323 }