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 static org.junit.Assert.assertEquals;
30  import static org.junit.Assert.assertFalse;
31  import static org.junit.Assert.assertNotNull;
32  import static org.junit.Assert.assertNull;
33  import static org.junit.Assert.assertSame;
34  import static org.junit.Assert.assertTrue;
35  
36  import java.io.ByteArrayInputStream;
37  import java.io.ByteArrayOutputStream;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.util.Date;
41  import java.util.HashMap;
42  import java.util.Map;
43  
44  import org.apache.http.Header;
45  import org.apache.http.HttpEntity;
46  import org.apache.http.HttpHost;
47  import org.apache.http.HttpRequest;
48  import org.apache.http.HttpResponse;
49  import org.apache.http.HttpStatus;
50  import org.apache.http.HttpVersion;
51  import org.apache.http.client.cache.HeaderConstants;
52  import org.apache.http.client.cache.HttpCacheEntry;
53  import org.apache.http.client.cache.Resource;
54  import org.apache.http.client.methods.HttpDelete;
55  import org.apache.http.client.methods.HttpGet;
56  import org.apache.http.client.methods.HttpHead;
57  import org.apache.http.client.methods.HttpOptions;
58  import org.apache.http.client.methods.HttpPost;
59  import org.apache.http.client.methods.HttpTrace;
60  import org.apache.http.client.utils.DateUtils;
61  import org.apache.http.entity.BasicHttpEntity;
62  import org.apache.http.entity.ByteArrayEntity;
63  import org.apache.http.message.BasicHeader;
64  import org.apache.http.message.BasicHttpResponse;
65  import org.junit.Assert;
66  import org.junit.Before;
67  import org.junit.Test;
68  
69  public class TestBasicHttpCache {
70  
71      private BasicHttpCache impl;
72      private SimpleHttpCacheStorage backing;
73  
74      @Before
75      public void setUp() throws Exception {
76          backing = new SimpleHttpCacheStorage();
77          impl = new BasicHttpCache(new HeapResourceFactory(), backing, CacheConfig.DEFAULT);
78      }
79  
80      @Test
81      public void testDoNotFlushCacheEntriesOnGet() throws Exception {
82          final HttpHost host = new HttpHost("foo.example.com");
83          final HttpRequest req = new HttpGet("/bar");
84          final String key = (new CacheKeyGenerator()).getURI(host, req);
85          final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
86  
87          backing.map.put(key, entry);
88  
89          impl.flushCacheEntriesFor(host, req);
90  
91          assertEquals(entry, backing.map.get(key));
92      }
93  
94      @Test
95      public void testDoNotFlushCacheEntriesOnHead() throws Exception {
96          final HttpHost host = new HttpHost("foo.example.com");
97          final HttpRequest req = new HttpHead("/bar");
98          final String key = (new CacheKeyGenerator()).getURI(host, req);
99          final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
100 
101         backing.map.put(key, entry);
102 
103         impl.flushCacheEntriesFor(host, req);
104 
105         assertEquals(entry, backing.map.get(key));
106     }
107 
108     @Test
109     public void testDoNotFlushCacheEntriesOnOptions() throws Exception {
110         final HttpHost host = new HttpHost("foo.example.com");
111         final HttpRequest req = new HttpOptions("/bar");
112         final String key = (new CacheKeyGenerator()).getURI(host, req);
113         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
114 
115         backing.map.put(key, entry);
116 
117         impl.flushCacheEntriesFor(host, req);
118 
119         assertEquals(entry, backing.map.get(key));
120     }
121 
122     @Test
123     public void testDoNotFlushCacheEntriesOnTrace() throws Exception {
124         final HttpHost host = new HttpHost("foo.example.com");
125         final HttpRequest req = new HttpTrace("/bar");
126         final String key = (new CacheKeyGenerator()).getURI(host, req);
127         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
128 
129         backing.map.put(key, entry);
130 
131         impl.flushCacheEntriesFor(host, req);
132 
133         assertEquals(entry, backing.map.get(key));
134     }
135 
136     @Test
137     public void testFlushContentLocationEntryIfUnSafeRequest()
138             throws Exception {
139         final HttpHost host = new HttpHost("foo.example.com");
140         final HttpRequest req = new HttpPost("/foo");
141         final HttpResponse resp = HttpTestUtils.make200Response();
142         resp.setHeader("Content-Location", "/bar");
143         resp.setHeader(HeaderConstants.ETAG, "\"etag\"");
144         final String key = (new CacheKeyGenerator()).getURI(host, new HttpGet("/bar"));
145 
146         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
147            new BasicHeader("Date", DateUtils.formatDate(new Date())),
148            new BasicHeader("ETag", "\"old-etag\"")
149         });
150 
151         backing.map.put(key, entry);
152 
153         impl.flushInvalidatedCacheEntriesFor(host, req, resp);
154 
155         assertNull(backing.map.get(key));
156     }
157 
158     @Test
159     public void testDoNotFlushContentLocationEntryIfSafeRequest()
160             throws Exception {
161         final HttpHost host = new HttpHost("foo.example.com");
162         final HttpRequest req = new HttpGet("/foo");
163         final HttpResponse resp = HttpTestUtils.make200Response();
164         resp.setHeader("Content-Location", "/bar");
165         final String key = (new CacheKeyGenerator()).getURI(host, new HttpGet("/bar"));
166 
167         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
168            new BasicHeader("Date", DateUtils.formatDate(new Date())),
169            new BasicHeader("ETag", "\"old-etag\"")
170         });
171 
172         backing.map.put(key, entry);
173 
174         impl.flushInvalidatedCacheEntriesFor(host, req, resp);
175 
176         assertEquals(entry, backing.map.get(key));
177     }
178 
179     @Test
180     public void testCanFlushCacheEntriesAtUri() throws Exception {
181         final HttpHost host = new HttpHost("foo.example.com");
182         final HttpRequest req = new HttpDelete("/bar");
183         final String key = (new CacheKeyGenerator()).getURI(host, req);
184         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
185 
186         backing.map.put(key, entry);
187 
188         impl.flushCacheEntriesFor(host, req);
189 
190         assertNull(backing.map.get(key));
191     }
192 
193     @Test
194     public void testRecognizesComplete200Response()
195         throws Exception {
196         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
197         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
198         resp.setEntity(new ByteArrayEntity(bytes));
199         resp.setHeader("Content-Length","128");
200         final Resource resource = new HeapResource(bytes);
201 
202         assertFalse(impl.isIncompleteResponse(resp, resource));
203     }
204 
205     @Test
206     public void testRecognizesComplete206Response()
207         throws Exception {
208         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT, "Partial Content");
209         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
210         final Resource resource = new HeapResource(bytes);
211         resp.setEntity(new ByteArrayEntity(bytes));
212         resp.setHeader("Content-Length","128");
213         resp.setHeader("Content-Range","bytes 0-127/255");
214 
215         assertFalse(impl.isIncompleteResponse(resp, resource));
216     }
217 
218     @Test
219     public void testRecognizesIncomplete200Response()
220         throws Exception {
221         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
222         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
223         final Resource resource = new HeapResource(bytes);
224         resp.setEntity(new ByteArrayEntity(bytes));
225         resp.setHeader("Content-Length","256");
226 
227         assertTrue(impl.isIncompleteResponse(resp, resource));
228     }
229 
230     @Test
231     public void testIgnoresIncompleteNon200Or206Responses()
232         throws Exception {
233         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_FORBIDDEN, "Forbidden");
234         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
235         final Resource resource = new HeapResource(bytes);
236         resp.setEntity(new ByteArrayEntity(bytes));
237         resp.setHeader("Content-Length","256");
238 
239         assertFalse(impl.isIncompleteResponse(resp, resource));
240     }
241 
242     @Test
243     public void testResponsesWithoutExplicitContentLengthAreComplete()
244         throws Exception {
245         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
246         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
247         final Resource resource = new HeapResource(bytes);
248         resp.setEntity(new ByteArrayEntity(bytes));
249 
250         assertFalse(impl.isIncompleteResponse(resp, resource));
251     }
252 
253     @Test
254     public void testResponsesWithUnparseableContentLengthHeaderAreComplete()
255         throws Exception {
256         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
257         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
258         final Resource resource = new HeapResource(bytes);
259         resp.setHeader("Content-Length","foo");
260         resp.setEntity(new ByteArrayEntity(bytes));
261 
262         assertFalse(impl.isIncompleteResponse(resp, resource));
263     }
264 
265     @Test
266     public void testNullResourcesAreComplete()
267         throws Exception {
268         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
269         resp.setHeader("Content-Length","256");
270 
271         assertFalse(impl.isIncompleteResponse(resp, null));
272     }
273 
274     @Test
275     public void testIncompleteResponseErrorProvidesPlainTextErrorMessage()
276         throws Exception {
277         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
278         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
279         final Resource resource = new HeapResource(bytes);
280         resp.setEntity(new ByteArrayEntity(bytes));
281         resp.setHeader("Content-Length","256");
282 
283         final HttpResponse result = impl.generateIncompleteResponseError(resp, resource);
284         final Header ctype = result.getFirstHeader("Content-Type");
285         assertEquals("text/plain;charset=UTF-8", ctype.getValue());
286     }
287 
288     @Test
289     public void testIncompleteResponseErrorProvidesNonEmptyErrorMessage()
290         throws Exception {
291         final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
292         final byte[] bytes = HttpTestUtils.getRandomBytes(128);
293         final Resource resource = new HeapResource(bytes);
294         resp.setEntity(new ByteArrayEntity(bytes));
295         resp.setHeader("Content-Length","256");
296 
297         final HttpResponse result = impl.generateIncompleteResponseError(resp, resource);
298         final int clen = Integer.parseInt(result.getFirstHeader("Content-Length").getValue());
299         assertTrue(clen > 0);
300         final HttpEntity body = result.getEntity();
301         if (body.getContentLength() < 0) {
302             final InputStream is = body.getContent();
303             int bytes_read = 0;
304             while((is.read()) != -1) {
305                 bytes_read++;
306             }
307             is.close();
308             assertEquals(clen, bytes_read);
309         } else {
310             assertTrue(body.getContentLength() == clen);
311         }
312     }
313 
314     @Test
315     public void testCacheUpdateAddsVariantURIToParentEntry() throws Exception {
316         final String parentCacheKey = "parentCacheKey";
317         final String variantCacheKey = "variantCacheKey";
318         final String existingVariantKey = "existingVariantKey";
319         final String newVariantCacheKey = "newVariantCacheKey";
320         final String newVariantKey = "newVariantKey";
321         final Map<String,String> existingVariants = new HashMap<String,String>();
322         existingVariants.put(existingVariantKey, variantCacheKey);
323         final HttpCacheEntry parent = HttpTestUtils.makeCacheEntry(existingVariants);
324         final HttpCacheEntry variant = HttpTestUtils.makeCacheEntry();
325 
326         final HttpCacheEntry result = impl.doGetUpdatedParentEntry(parentCacheKey, parent, variant, newVariantKey, newVariantCacheKey);
327         final Map<String,String> resultMap = result.getVariantMap();
328         assertEquals(2, resultMap.size());
329         assertEquals(variantCacheKey, resultMap.get(existingVariantKey));
330         assertEquals(newVariantCacheKey, resultMap.get(newVariantKey));
331     }
332 
333     @Test
334     public void testStoreInCachePutsNonVariantEntryInPlace() throws Exception {
335         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
336         assertFalse(entry.hasVariants());
337         final HttpHost host = new HttpHost("foo.example.com");
338         final HttpRequest req = new HttpGet("http://foo.example.com/bar");
339         final String key = (new CacheKeyGenerator()).getURI(host, req);
340 
341         impl.storeInCache(host, req, entry);
342         assertSame(entry, backing.map.get(key));
343     }
344 
345     @Test
346     public void testTooLargeResponsesAreNotCached() throws Exception {
347         final HttpHost host = new HttpHost("foo.example.com");
348         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
349 
350         final Date now = new Date();
351         final Date requestSent = new Date(now.getTime() - 3 * 1000L);
352         final Date responseGenerated = new Date(now.getTime() - 2 * 1000L);
353         final Date responseReceived = new Date(now.getTime() - 1 * 1000L);
354 
355         final HttpResponse originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
356         originResponse.setEntity(HttpTestUtils.makeBody(CacheConfig.DEFAULT_MAX_OBJECT_SIZE_BYTES + 1));
357         originResponse.setHeader("Cache-Control","public, max-age=3600");
358         originResponse.setHeader("Date", DateUtils.formatDate(responseGenerated));
359         originResponse.setHeader("ETag", "\"etag\"");
360 
361         final HttpResponse result = impl.cacheAndReturnResponse(host, request, originResponse, requestSent, responseReceived);
362         assertEquals(0, backing.map.size());
363         assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result));
364     }
365 
366 
367     @Test
368     public void testSmallEnoughResponsesAreCached() throws Exception {
369         final HttpHost host = new HttpHost("foo.example.com");
370         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
371 
372         final Date now = new Date();
373         final Date requestSent = new Date(now.getTime() - 3 * 1000L);
374         final Date responseGenerated = new Date(now.getTime() - 2 * 1000L);
375         final Date responseReceived = new Date(now.getTime() - 1 * 1000L);
376 
377         final HttpResponse originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
378         originResponse.setEntity(HttpTestUtils.makeBody(CacheConfig.DEFAULT_MAX_OBJECT_SIZE_BYTES - 1));
379         originResponse.setHeader("Cache-Control","public, max-age=3600");
380         originResponse.setHeader("Date", DateUtils.formatDate(responseGenerated));
381         originResponse.setHeader("ETag", "\"etag\"");
382 
383         final HttpResponse result = impl.cacheAndReturnResponse(host, request, originResponse, requestSent, responseReceived);
384         assertEquals(1, backing.map.size());
385         assertTrue(backing.map.containsKey((new CacheKeyGenerator()).getURI(host, request)));
386         assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result));
387     }
388 
389     @Test
390     public void testGetCacheEntryReturnsNullOnCacheMiss() throws Exception {
391         final HttpHost host = new HttpHost("foo.example.com");
392         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
393         final HttpCacheEntry result = impl.getCacheEntry(host, request);
394         Assert.assertNull(result);
395     }
396 
397     @Test
398     public void testGetCacheEntryFetchesFromCacheOnCacheHitIfNoVariants() throws Exception {
399         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
400         assertFalse(entry.hasVariants());
401         final HttpHost host = new HttpHost("foo.example.com");
402         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
403 
404         final String key = (new CacheKeyGenerator()).getURI(host, request);
405 
406         backing.map.put(key,entry);
407 
408         final HttpCacheEntry result = impl.getCacheEntry(host, request);
409         Assert.assertSame(entry, result);
410     }
411 
412     @Test
413     public void testGetCacheEntryReturnsNullIfNoVariantInCache() throws Exception {
414         final HttpHost host = new HttpHost("foo.example.com");
415         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
416 
417         final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar");
418         origRequest.setHeader("Accept-Encoding","gzip");
419 
420         final HttpResponse origResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
421         origResponse.setEntity(HttpTestUtils.makeBody(128));
422         origResponse.setHeader("Date", DateUtils.formatDate(new Date()));
423         origResponse.setHeader("Cache-Control", "max-age=3600, public");
424         origResponse.setHeader("ETag", "\"etag\"");
425         origResponse.setHeader("Vary", "Accept-Encoding");
426         origResponse.setHeader("Content-Encoding","gzip");
427 
428         impl.cacheAndReturnResponse(host, origRequest, origResponse, new Date(), new Date());
429         final HttpCacheEntry result = impl.getCacheEntry(host, request);
430         assertNull(result);
431     }
432 
433     @Test
434     public void testGetCacheEntryReturnsVariantIfPresentInCache() throws Exception {
435         final HttpHost host = new HttpHost("foo.example.com");
436         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
437         request.setHeader("Accept-Encoding","gzip");
438 
439         final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar");
440         origRequest.setHeader("Accept-Encoding","gzip");
441 
442         final HttpResponse origResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
443         origResponse.setEntity(HttpTestUtils.makeBody(128));
444         origResponse.setHeader("Date", DateUtils.formatDate(new Date()));
445         origResponse.setHeader("Cache-Control", "max-age=3600, public");
446         origResponse.setHeader("ETag", "\"etag\"");
447         origResponse.setHeader("Vary", "Accept-Encoding");
448         origResponse.setHeader("Content-Encoding","gzip");
449 
450         impl.cacheAndReturnResponse(host, origRequest, origResponse, new Date(), new Date());
451         final HttpCacheEntry result = impl.getCacheEntry(host, request);
452         assertNotNull(result);
453     }
454 
455     @Test
456     public void testGetVariantCacheEntriesReturnsEmptySetOnNoVariants() throws Exception {
457         final HttpHost host = new HttpHost("foo.example.com");
458         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
459 
460         final Map<String,Variant> variants = impl.getVariantCacheEntriesWithEtags(host, request);
461 
462         assertNotNull(variants);
463         assertEquals(0, variants.size());
464     }
465 
466     @Test
467     public void testGetVariantCacheEntriesReturnsAllVariants() throws Exception {
468         final HttpHost host = new HttpHost("foo.example.com");
469         final HttpRequest req1 = new HttpGet("http://foo.example.com/bar");
470         req1.setHeader("Accept-Encoding", "gzip");
471 
472         final HttpResponse resp1 = HttpTestUtils.make200Response();
473         resp1.setHeader("Date", DateUtils.formatDate(new Date()));
474         resp1.setHeader("Cache-Control", "max-age=3600, public");
475         resp1.setHeader("ETag", "\"etag1\"");
476         resp1.setHeader("Vary", "Accept-Encoding");
477         resp1.setHeader("Content-Encoding","gzip");
478         resp1.setHeader("Vary", "Accept-Encoding");
479 
480         final HttpRequest req2 = new HttpGet("http://foo.example.com/bar");
481         req2.setHeader("Accept-Encoding", "identity");
482 
483         final HttpResponse resp2 = HttpTestUtils.make200Response();
484         resp2.setHeader("Date", DateUtils.formatDate(new Date()));
485         resp2.setHeader("Cache-Control", "max-age=3600, public");
486         resp2.setHeader("ETag", "\"etag2\"");
487         resp2.setHeader("Vary", "Accept-Encoding");
488         resp2.setHeader("Content-Encoding","gzip");
489         resp2.setHeader("Vary", "Accept-Encoding");
490 
491         impl.cacheAndReturnResponse(host, req1, resp1, new Date(), new Date());
492         impl.cacheAndReturnResponse(host, req2, resp2, new Date(), new Date());
493 
494         final Map<String,Variant> variants = impl.getVariantCacheEntriesWithEtags(host, req1);
495 
496         assertNotNull(variants);
497         assertEquals(2, variants.size());
498 
499     }
500 
501     @Test
502     public void testOriginalResponseWithNoContentSizeHeaderIsReleased() throws Exception {
503         final HttpHost host = new HttpHost("foo.example.com");
504         final HttpRequest request = new HttpGet("http://foo.example.com/bar");
505 
506         final Date now = new Date();
507         final Date requestSent = new Date(now.getTime() - 3 * 1000L);
508         final Date responseGenerated = new Date(now.getTime() - 2 * 1000L);
509         final Date responseReceived = new Date(now.getTime() - 1 * 1000L);
510 
511         final HttpResponse originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
512         final BasicHttpEntity entity = new BasicHttpEntity();
513         final ConsumableInputStream inputStream = new ConsumableInputStream(new ByteArrayInputStream(HttpTestUtils.getRandomBytes(CacheConfig.DEFAULT_MAX_OBJECT_SIZE_BYTES - 1)));
514         entity.setContent(inputStream);
515         originResponse.setEntity(entity);
516         originResponse.setHeader("Cache-Control","public, max-age=3600");
517         originResponse.setHeader("Date", DateUtils.formatDate(responseGenerated));
518         originResponse.setHeader("ETag", "\"etag\"");
519 
520         final HttpResponse result = impl.cacheAndReturnResponse(host, request, originResponse, requestSent, responseReceived);
521         IOUtils.consume(result.getEntity());
522         assertTrue(inputStream.wasClosed());
523     }
524 
525     static class DisposableResource implements Resource {
526 
527         private static final long serialVersionUID = 1L;
528 
529         private final byte[] b;
530         private boolean dispoased;
531 
532         public DisposableResource(final byte[] b) {
533             super();
534             this.b = b;
535         }
536 
537         byte[] getByteArray() {
538             return this.b;
539         }
540 
541         @Override
542         public InputStream getInputStream() throws IOException {
543             if (dispoased) {
544                 throw new IOException("Already dispoased");
545             }
546             return new ByteArrayInputStream(this.b);
547         }
548 
549         @Override
550         public long length() {
551             return this.b.length;
552         }
553 
554         @Override
555         public void dispose() {
556             this.dispoased = true;
557         }
558 
559     }
560 
561     @Test
562     public void testEntryUpdate() throws Exception {
563 
564         final HeapResourceFactory rf = new HeapResourceFactory() {
565 
566             @Override
567             Resource createResource(final byte[] buf) {
568                 return new DisposableResource(buf);
569             }
570 
571         };
572 
573         impl = new BasicHttpCache(rf, backing, CacheConfig.DEFAULT);
574 
575         final HttpHost host = new HttpHost("foo.example.com");
576 
577         final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar");
578         origRequest.setHeader("Accept-Encoding","gzip");
579 
580         final HttpResponse origResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
581         origResponse.setEntity(HttpTestUtils.makeBody(128));
582         origResponse.setHeader("Date", DateUtils.formatDate(new Date()));
583         origResponse.setHeader("Cache-Control", "max-age=3600, public");
584         origResponse.setHeader("ETag", "\"etag\"");
585         origResponse.setHeader("Vary", "Accept-Encoding");
586         origResponse.setHeader("Content-Encoding","gzip");
587 
588         final HttpResponse response = impl.cacheAndReturnResponse(
589                 host, origRequest, origResponse, new Date(), new Date());
590         final HttpEntity entity = response.getEntity();
591         Assert.assertNotNull(entity);
592         IOUtils.copyAndClose(entity.getContent(), new ByteArrayOutputStream());
593     }
594 
595 }