boolean isIncompleteResponse(final HttpResponse resp, final Resource resource) { final int status = resp.getStatusLine().getStatusCode(); if (status != HttpStatus.SC_OK && status != HttpStatus.SC_PARTIAL_CONTENT) { return false; } final Header hdr = resp.getFirstHeader(HTTP.CONTENT_LEN); if (hdr == null) { return false; } final int contentLength; try { contentLength = Integer.parseInt(hdr.getValue()); } catch (final NumberFormatException nfe) { return false; } if (resource == null) { return false; } return (resource.length() < contentLength); }
HttpCacheEntry doGetUpdatedParentEntry( final String requestId, final HttpCacheEntry existing, final HttpCacheEntry entry, final String variantKey, final String variantCacheKey) throws IOException { HttpCacheEntry src = existing; if (src == null) { src = entry; } Resource resource = null; if (src.getResource() != null) { resource = resourceFactory.copy(requestId, src.getResource()); } final Map<String,String> variantMap = new HashMap<String,String>(src.getVariantMap()); variantMap.put(variantKey, variantCacheKey); return new HttpCacheEntry( src.getRequestDate(), src.getResponseDate(), src.getStatusLine(), src.getAllHeaders(), resource, variantMap, src.getRequestMethod()); }
/** * Update the entry with the new information from the response. Should only be used for * 304 responses. * * @param requestId * @param entry The cache Entry to be updated * @param requestDate When the request was performed * @param responseDate When the response was gotten * @param response The HttpResponse from the backend server call * @return HttpCacheEntry an updated version of the cache entry * @throws java.io.IOException if something bad happens while trying to read the body from the original entry */ public HttpCacheEntry updateCacheEntry( final String requestId, final HttpCacheEntry entry, final Date requestDate, final Date responseDate, final HttpResponse response) throws IOException { Args.check(response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED, "Response must have 304 status code"); final Header[] mergedHeaders = mergeHeaders(entry, response); Resource resource = null; if (entry.getResource() != null) { resource = resourceFactory.copy(requestId, entry.getResource()); } return new HttpCacheEntry( requestDate, responseDate, entry.getStatusLine(), mergedHeaders, resource, entry.getRequestMethod()); }
@Override public Resource generate( final String requestId, final InputStream instream, final InputLimit limit) throws IOException { final File file = generateUniqueCacheFile(requestId); final FileOutputStream outstream = new FileOutputStream(file); try { final byte[] buf = new byte[2048]; long total = 0; int l; while ((l = instream.read(buf)) != -1) { outstream.write(buf, 0, l); total += l; if (limit != null && total > limit.getValue()) { limit.reached(); break; } } } finally { outstream.close(); } return new FileResource(file); }
@Override public Resource generate( final String requestId, final InputStream instream, final InputLimit limit) throws IOException { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); final byte[] buf = new byte[2048]; long total = 0; int l; while ((l = instream.read(buf)) != -1) { outstream.write(buf, 0, l); total += l; if (limit != null && total > limit.getValue()) { limit.reached(); break; } } return createResource(outstream.toByteArray()); }
private byte[] resourceToBytes(final Resource res) throws IOException { final InputStream inputStream = res.getInputStream(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int readBytes; final byte[] bytes = new byte[8096]; while ((readBytes = inputStream.read(bytes)) > 0) { outputStream.write(bytes, 0, readBytes); } final byte[] byteData = outputStream.toByteArray(); inputStream.close(); outputStream.close(); return byteData; }
@Test public void testCombinedEntityBasics() throws Exception { final Resource resource = mock(Resource.class); when(resource.getInputStream()).thenReturn( new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 })); final ByteArrayInputStream instream = new ByteArrayInputStream(new byte[] { 6, 7, 8, 9, 10 }); final CombinedEntity entity = new CombinedEntity(resource, instream); Assert.assertEquals(-1, entity.getContentLength()); Assert.assertFalse(entity.isRepeatable()); Assert.assertTrue(entity.isStreaming()); final byte[] result = EntityUtils.toByteArray(entity); Assert.assertArrayEquals(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, result); verify(resource).getInputStream(); verify(resource).dispose(); }
@Test public void testIncompleteResponseErrorProvidesNonEmptyErrorMessage() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setEntity(new ByteArrayEntity(bytes)); resp.setHeader("Content-Length","256"); final HttpResponse result = impl.generateIncompleteResponseError(resp, resource); final int clen = Integer.parseInt(result.getFirstHeader("Content-Length").getValue()); assertTrue(clen > 0); final HttpEntity body = result.getEntity(); if (body.getContentLength() < 0) { final InputStream is = body.getContent(); int bytes_read = 0; while((is.read()) != -1) { bytes_read++; } is.close(); assertEquals(clen, bytes_read); } else { assertTrue(body.getContentLength() == clen); } }
CloseableHttpResponse generateIncompleteResponseError( final HttpResponse response, final Resource resource) { final Integer contentLength = Integer.valueOf(response.getFirstHeader(HTTP.CONTENT_LEN).getValue()); final HttpResponse error = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_GATEWAY, "Bad Gateway"); error.setHeader("Content-Type","text/plain;charset=UTF-8"); final String msg = String.format("Received incomplete response " + "with Content-Length %d but actual body length %d", contentLength, resource.length()); final byte[] msgBytes = msg.getBytes(); error.setHeader("Content-Length", Integer.toString(msgBytes.length)); error.setEntity(new ByteArrayEntity(msgBytes)); return Proxies.enhanceResponse(error); }
@Override public CloseableHttpResponse cacheAndReturnResponse( final HttpHost host, final HttpRequest request, final CloseableHttpResponse originResponse, final Date requestSent, final Date responseReceived) throws IOException { boolean closeOriginResponse = true; final SizeLimitedResponseReader responseReader = getResponseReader(request, originResponse); try { responseReader.readResponse(); if (responseReader.isLimitReached()) { closeOriginResponse = false; return responseReader.getReconstructedResponse(); } final Resource resource = responseReader.getResource(); if (isIncompleteResponse(originResponse, resource)) { return generateIncompleteResponseError(originResponse, resource); } final HttpCacheEntry entry = new HttpCacheEntry( requestSent, responseReceived, originResponse.getStatusLine(), originResponse.getAllHeaders(), resource, request.getRequestLine().getMethod()); storeInCache(host, request, entry); return responseGenerator.generateResponse(HttpRequestWrapper.wrap(request, host), entry); } finally { if (closeOriginResponse) { originResponse.close(); } } }
@Override public Resource copy( final String requestId, final Resource resource) throws IOException { final File file = generateUniqueCacheFile(requestId); if (resource instanceof FileResource) { final File src = ((FileResource) resource).getFile(); IOUtils.copyFile(src, file); } else { final FileOutputStream out = new FileOutputStream(file); IOUtils.copyAndClose(resource.getInputStream(), out); } return new FileResource(file); }
@Override public Resource copy( final String requestId, final Resource resource) throws IOException { byte[] body; if (resource instanceof HeapResource) { body = ((HeapResource) resource).getByteArray(); } else { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); IOUtils.copyAndClose(resource.getInputStream(), outstream); body = outstream.toByteArray(); } return createResource(body); }
private void keepResourceReference(final HttpCacheEntry entry) { final Resource resource = entry.getResource(); if (resource != null) { // Must deallocate the resource when the entry is no longer in used final ResourceReference ref = new ResourceReference(entry, this.morque); this.resources.add(ref); } }
@Test public void testRecognizesComplete200Response() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); resp.setEntity(new ByteArrayEntity(bytes)); resp.setHeader("Content-Length","128"); final Resource resource = new HeapResource(bytes); assertFalse(impl.isIncompleteResponse(resp, resource)); }
@Test public void testRecognizesComplete206Response() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT, "Partial Content"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setEntity(new ByteArrayEntity(bytes)); resp.setHeader("Content-Length","128"); resp.setHeader("Content-Range","bytes 0-127/255"); assertFalse(impl.isIncompleteResponse(resp, resource)); }
@Test public void testRecognizesIncomplete200Response() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setEntity(new ByteArrayEntity(bytes)); resp.setHeader("Content-Length","256"); assertTrue(impl.isIncompleteResponse(resp, resource)); }
@Test public void testIgnoresIncompleteNon200Or206Responses() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_FORBIDDEN, "Forbidden"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setEntity(new ByteArrayEntity(bytes)); resp.setHeader("Content-Length","256"); assertFalse(impl.isIncompleteResponse(resp, resource)); }
@Test public void testResponsesWithoutExplicitContentLengthAreComplete() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setEntity(new ByteArrayEntity(bytes)); assertFalse(impl.isIncompleteResponse(resp, resource)); }
@Test public void testResponsesWithUnparseableContentLengthHeaderAreComplete() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setHeader("Content-Length","foo"); resp.setEntity(new ByteArrayEntity(bytes)); assertFalse(impl.isIncompleteResponse(resp, resource)); }
@Test public void testIncompleteResponseErrorProvidesPlainTextErrorMessage() throws Exception { final HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final byte[] bytes = HttpTestUtils.getRandomBytes(128); final Resource resource = new HeapResource(bytes); resp.setEntity(new ByteArrayEntity(bytes)); resp.setHeader("Content-Length","256"); final HttpResponse result = impl.generateIncompleteResponseError(resp, resource); final Header ctype = result.getFirstHeader("Content-Type"); assertEquals("text/plain;charset=UTF-8", ctype.getValue()); }
@Test public void testEntryUpdate() throws Exception { final HeapResourceFactory rf = new HeapResourceFactory() { @Override Resource createResource(final byte[] buf) { return new DisposableResource(buf); } }; impl = new BasicHttpCache(rf, backing, CacheConfig.DEFAULT); final HttpHost host = new HttpHost("foo.example.com"); final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar"); origRequest.setHeader("Accept-Encoding","gzip"); final HttpResponse origResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); origResponse.setEntity(HttpTestUtils.makeBody(128)); origResponse.setHeader("Date", DateUtils.formatDate(new Date())); origResponse.setHeader("Cache-Control", "max-age=3600, public"); origResponse.setHeader("ETag", "\"etag\""); origResponse.setHeader("Vary", "Accept-Encoding"); origResponse.setHeader("Content-Encoding","gzip"); final HttpResponse response = impl.cacheAndReturnResponse( host, origRequest, origResponse, new Date(), new Date()); final HttpEntity entity = response.getEntity(); Assert.assertNotNull(entity); IOUtils.copyAndClose(entity.getContent(), new ByteArrayOutputStream()); }
private HttpResponse generateResponse(HttpCacheEntry entry) throws IOException { HttpResponse response = new BasicHttpResponse(entry.getProtocolVersion(), entry .getStatusCode(), entry.getReasonPhrase()); Resource resource = entry.getResource(); InputStreamEntity entity = new InputStreamEntity(resource.getInputStream(), resource.length()); entity.setContentType(entry.getFirstHeader(HTTP.CONTENT_TYPE)); entity.setContentEncoding(entry.getFirstHeader(HTTP.CONTENT_ENCODING)); response.setHeaders(entry.getAllHeaders()); response.setEntity(entity); return response; }
private Resource createResource(HttpRequest request, HttpResponse response) throws IOException { HttpEntity entity = response.getEntity(); if (entity == null) { return null; } String uri = request.getRequestLine().getUri(); InputStream instream = entity.getContent(); return new HeapResourceFactory().generate(uri, instream, null); }
private HttpCacheEntry makeHttpCacheEntry() { final Date now = new Date(); final StatusLine statusLine = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); final Header[] headers = { new BasicHeader("Date", DateUtils.formatDate(now)), new BasicHeader("Server", "MockServer/1.0") }; final Resource resource = new HeapResource(new byte[0]); HttpCacheEntry entry = new HttpCacheEntry(now, now, statusLine, headers, resource); return entry; }
Resource getResource() { ensureConsumed(); return resource; }
Resource createResource(final byte[] buf) { return new HeapResource(buf); }
public Resource getResource() { return this.resource; }
CombinedEntity(final Resource resource, final InputStream instream) throws IOException { super(); this.resource = resource; this.combinedStream = new SequenceInputStream( new ResourceStream(resource.getInputStream()), instream); }