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