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