diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/InputLimit.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/InputLimit.java
new file mode 100644
index 000000000..f85faaf88
--- /dev/null
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/InputLimit.java
@@ -0,0 +1,55 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.client.cache;
+
+/**
+ * @since 4.1
+ */
+public class InputLimit {
+
+ private final long value;
+ private boolean reached;
+
+ public InputLimit(long value) {
+ super();
+ this.value = value;
+ this.reached = false;
+ }
+
+ public long getValue() {
+ return this.value;
+ }
+
+ public void reached() {
+ this.reached = true;
+ }
+
+ public boolean isReached() {
+ return this.reached;
+ }
+
+}
diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/ResourceFactory.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/ResourceFactory.java
index 8e61a8bb1..063b842e1 100644
--- a/httpclient-cache/src/main/java/org/apache/http/client/cache/ResourceFactory.java
+++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/ResourceFactory.java
@@ -27,6 +27,7 @@
package org.apache.http.client.cache;
import java.io.IOException;
+import java.io.InputStream;
/**
* Generates {@link Resource} instances.
@@ -35,7 +36,7 @@ import java.io.IOException;
*/
public interface ResourceFactory {
- Resource generate(String requestId, byte[] body) throws IOException;
+ Resource generate(String requestId, InputStream instream, InputLimit limit) throws IOException;
Resource copy(String requestId, Resource resource) throws IOException;
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
index 277fe7c46..1161e0d22 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java
@@ -602,8 +602,7 @@ public class CachingHttpClient implements HttpClient {
variants);
}
- HttpResponse correctIncompleteResponse(HttpResponse resp,
- byte[] bodyBytes) {
+ HttpResponse correctIncompleteResponse(HttpResponse resp, Resource resource) {
int status = resp.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK
&& status != HttpStatus.SC_PARTIAL_CONTENT) {
@@ -617,13 +616,14 @@ public class CachingHttpClient implements HttpClient {
} catch (NumberFormatException nfe) {
return resp;
}
- if (bodyBytes.length >= contentLength) return resp;
+ if (resource.length() >= contentLength) return resp;
HttpResponse error =
new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_GATEWAY, "Bad Gateway");
error.setHeader("Content-Type","text/plain;charset=UTF-8");
- String msg = String.format("Received incomplete response with Content-Length %d but actual body length %d", contentLength, bodyBytes.length);
+ String msg = String.format("Received incomplete response " +
+ "with Content-Length %d but actual body length %d", contentLength, resource.length());
byte[] msgBytes = msg.getBytes();
- error.setHeader("Content-Length", String.format("%d",msgBytes.length));
+ error.setHeader("Content-Length", Integer.toString(msgBytes.length));
error.setEntity(new ByteArrayEntity(msgBytes));
return error;
}
@@ -643,19 +643,17 @@ public class CachingHttpClient implements HttpClient {
HttpResponse corrected = backendResponse;
if (cacheable) {
- SizeLimitedResponseReader responseReader = getResponseReader(backendResponse);
+ SizeLimitedResponseReader responseReader = getResponseReader(request, backendResponse);
+ responseReader.readResponse();
- if (responseReader.isResponseTooLarge()) {
+ if (responseReader.isLimitReached()) {
return responseReader.getReconstructedResponse();
}
- byte[] responseBytes = responseReader.getResponseBytes();
- corrected = correctIncompleteResponse(backendResponse,
- responseBytes);
+ Resource resource = responseReader.getResource();
+ corrected = correctIncompleteResponse(backendResponse, resource);
int correctedStatus = corrected.getStatusLine().getStatusCode();
if (HttpStatus.SC_BAD_GATEWAY != correctedStatus) {
- Resource resource = resourceFactory.generate(
- request.getRequestLine().getUri(), responseBytes);
HttpCacheEntry entry = new HttpCacheEntry(
requestDate,
responseDate,
@@ -673,8 +671,9 @@ public class CachingHttpClient implements HttpClient {
return corrected;
}
- SizeLimitedResponseReader getResponseReader(HttpResponse backEndResponse) {
- return new SizeLimitedResponseReader(maxObjectSizeBytes, backEndResponse);
+ SizeLimitedResponseReader getResponseReader(HttpRequest request, HttpResponse backEndResponse) {
+ return new SizeLimitedResponseReader(
+ resourceFactory, maxObjectSizeBytes, request, backEndResponse);
}
}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java
new file mode 100644
index 000000000..a0ef1892a
--- /dev/null
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedEntity.java
@@ -0,0 +1,105 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.impl.client.cache;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.SequenceInputStream;
+
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.client.cache.Resource;
+import org.apache.http.entity.AbstractHttpEntity;
+
+@NotThreadSafe
+class CombinedEntity extends AbstractHttpEntity {
+
+ private final Resource resource;
+ private final InputStream combinedStream;
+
+ CombinedEntity(final Resource resource, final InputStream instream) throws IOException {
+ super();
+ this.resource = resource;
+ this.combinedStream = new SequenceInputStream(
+ new ResourceStream(resource.getInputStream()), instream);
+ }
+
+ public long getContentLength() {
+ return -1;
+ }
+
+ public boolean isRepeatable() {
+ return false;
+ }
+
+ public boolean isStreaming() {
+ return true;
+ }
+
+ public InputStream getContent() throws IOException, IllegalStateException {
+ return this.combinedStream;
+ }
+
+ public void writeTo(final OutputStream outstream) throws IOException {
+ if (outstream == null) {
+ throw new IllegalArgumentException("Output stream may not be null");
+ }
+ InputStream instream = getContent();
+ try {
+ int l;
+ byte[] tmp = new byte[2048];
+ while ((l = instream.read(tmp)) != -1) {
+ outstream.write(tmp, 0, l);
+ }
+ } finally {
+ instream.close();
+ }
+ }
+
+ private void dispose() {
+ this.resource.dispose();
+ }
+
+ class ResourceStream extends FilterInputStream {
+
+ protected ResourceStream(final InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ super.close();
+ } finally {
+ dispose();
+ }
+ }
+
+ }
+
+}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedInputStream.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedInputStream.java
deleted file mode 100644
index 9c681ba4e..000000000
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CombinedInputStream.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- *
- */
-package org.apache.http.impl.client.cache;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A class that presents two inputstreams as a single stream
- *
- * @since 4.1
- */
-class CombinedInputStream extends InputStream {
-
- private final InputStream inputStream1;
- private final InputStream inputStream2;
-
- /**
- * Take two inputstreams and produce an object that makes them appear as if they
- * are actually a 'single' input stream.
- *
- * @param inputStream1
- * First stream to read
- * @param inputStream2
- * Second stream to read
- */
- public CombinedInputStream(InputStream inputStream1, InputStream inputStream2) {
- if (inputStream1 == null)
- throw new IllegalArgumentException("inputStream1 cannot be null");
- if (inputStream2 == null)
- throw new IllegalArgumentException("inputStream2 cannot be null");
-
- this.inputStream1 = inputStream1;
- this.inputStream2 = inputStream2;
- }
-
- @Override
- public int available() throws IOException {
- return inputStream1.available() + inputStream2.available();
- }
-
- @Override
- public int read() throws IOException {
- int result = inputStream1.read();
-
- if (result == -1)
- result = inputStream2.read();
-
- return result;
- }
-}
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java
index abacc6c9e..71746f71f 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/FileResourceFactory.java
@@ -29,8 +29,10 @@ package org.apache.http.impl.client.cache;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import org.apache.http.annotation.Immutable;
+import org.apache.http.client.cache.InputLimit;
import org.apache.http.client.cache.Resource;
import org.apache.http.client.cache.ResourceFactory;
@@ -67,18 +69,33 @@ public class FileResourceFactory implements ResourceFactory {
return new File(this.cacheDir, buffer.toString());
}
- public Resource generate(final String requestId, final byte[] body) throws IOException {
+ public Resource generate(
+ final String requestId,
+ final InputStream instream,
+ final InputLimit limit) throws IOException {
File file = generateUniqueCacheFile(requestId);
FileOutputStream outstream = new FileOutputStream(file);
try {
- outstream.write(body);
+ 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);
}
- public Resource copy(final String requestId, final Resource resource) throws IOException {
+ public Resource copy(
+ final String requestId,
+ final Resource resource) throws IOException {
File file = generateUniqueCacheFile(requestId);
if (resource instanceof FileResource) {
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java
index a950d8037..d4e7bd992 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HeapResourceFactory.java
@@ -28,8 +28,10 @@ package org.apache.http.impl.client.cache;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import org.apache.http.annotation.Immutable;
+import org.apache.http.client.cache.InputLimit;
import org.apache.http.client.cache.Resource;
import org.apache.http.client.cache.ResourceFactory;
@@ -41,11 +43,28 @@ import org.apache.http.client.cache.ResourceFactory;
@Immutable
public class HeapResourceFactory implements ResourceFactory {
- public Resource generate(final String requestId, final byte[] body) throws IOException {
- return new HeapResource(body);
+ public Resource generate(
+ final String requestId,
+ final InputStream instream,
+ final InputLimit limit) throws IOException {
+ ByteArrayOutputStream outstream = new ByteArrayOutputStream();
+ 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 new HeapResource(outstream.toByteArray());
}
- public Resource copy(final String requestId, final Resource resource) throws IOException {
+ public Resource copy(
+ final String requestId,
+ final Resource resource) throws IOException {
byte[] body;
if (resource instanceof HeapResource) {
body = ((HeapResource) resource).getByteArray();
diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java
index 73b15156d..b142bb6c0 100644
--- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java
+++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/SizeLimitedResponseReader.java
@@ -26,132 +26,101 @@
*/
package org.apache.http.impl.client.cache;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
+import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
-import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.client.cache.InputLimit;
+import org.apache.http.client.cache.Resource;
+import org.apache.http.client.cache.ResourceFactory;
import org.apache.http.message.BasicHttpResponse;
/**
* @since 4.1
*/
+@NotThreadSafe
class SizeLimitedResponseReader {
- private final int maxResponseSizeBytes;
+ private final ResourceFactory resourceFactory;
+ private final long maxResponseSizeBytes;
+ private final HttpRequest request;
private final HttpResponse response;
- private ByteArrayOutputStream outputStream;
- private InputStream contentInputStream;
- private boolean isTooLarge;
- private boolean responseIsConsumed;
- private byte[] sizeLimitedContent;
- private boolean outputStreamConsumed;
+ private InputStream instream;
+ private InputLimit limit;
+ private Resource resource;
+ private boolean consumed;
/**
* Create an {@link HttpResponse} that is limited in size, this allows for checking
* the size of objects that will be stored in the cache.
- *
- * @param maxResponseSizeBytes
- * Maximum size that a response can be to be eligible for cache inclusion
- *
- * @param response
- * The {@link HttpResponse}
*/
- public SizeLimitedResponseReader(int maxResponseSizeBytes, HttpResponse response) {
+ public SizeLimitedResponseReader(
+ ResourceFactory resourceFactory,
+ long maxResponseSizeBytes,
+ HttpRequest request,
+ HttpResponse response) {
+ super();
+ this.resourceFactory = resourceFactory;
this.maxResponseSizeBytes = maxResponseSizeBytes;
+ this.request = request;
this.response = response;
}
- protected boolean isResponseTooLarge() throws IOException {
- if (!responseIsConsumed)
- isTooLarge = consumeResponse();
-
- return isTooLarge;
+ protected void readResponse() throws IOException {
+ if (!consumed) {
+ doConsume();
+ }
}
- private boolean consumeResponse() throws IOException {
+ private void ensureNotConsumed() {
+ if (consumed) {
+ throw new IllegalStateException("Response has already been consumed");
+ }
+ }
- if (responseIsConsumed)
- throw new IllegalStateException(
- "You cannot call this method more than once, because it consumes an underlying stream");
+ private void ensureConsumed() {
+ if (!consumed) {
+ throw new IllegalStateException("Response has not been consumed");
+ }
+ }
- responseIsConsumed = true;
+ private void doConsume() throws IOException {
+ ensureNotConsumed();
+ consumed = true;
+
+ limit = new InputLimit(maxResponseSizeBytes);
HttpEntity entity = response.getEntity();
- if (entity == null)
- return false;
-
- contentInputStream = entity.getContent();
- int bytes = 0;
-
- outputStream = new ByteArrayOutputStream();
-
- int current;
-
- while (bytes < maxResponseSizeBytes && (current = contentInputStream.read()) != -1) {
- outputStream.write(current);
- bytes++;
+ if (entity == null) {
+ return;
}
-
- if ((current = contentInputStream.read()) != -1) {
- outputStream.write(current);
- return true;
- }
-
- return false;
+ String uri = request.getRequestLine().getUri();
+ instream = entity.getContent();
+ resource = resourceFactory.generate(uri, instream, limit);
}
- private void consumeOutputStream() {
- if (outputStreamConsumed)
- throw new IllegalStateException(
- "underlying output stream has already been written to byte[]");
-
- if (!responseIsConsumed)
- throw new IllegalStateException("Must call consumeResponse first.");
-
- sizeLimitedContent = outputStream.toByteArray();
- outputStreamConsumed = true;
+ boolean isLimitReached() {
+ ensureConsumed();
+ return limit.isReached();
}
- protected byte[] getResponseBytes() {
- if (!outputStreamConsumed)
- consumeOutputStream();
-
- return sizeLimitedContent;
+ Resource getResource() {
+ ensureConsumed();
+ return resource;
}
- protected HttpResponse getReconstructedResponse() {
-
- InputStream combinedStream = getCombinedInputStream();
-
- return constructResponse(response, combinedStream);
- }
-
- protected InputStream getCombinedInputStream() {
- InputStream input1 = new ByteArrayInputStream(getResponseBytes());
- InputStream input2 = getContentInputStream();
- return new CombinedInputStream(input1, input2);
- }
-
- protected InputStream getContentInputStream() {
- return contentInputStream;
- }
-
- protected HttpResponse constructResponse(HttpResponse originalResponse,
- InputStream combinedStream) {
- HttpResponse response = new BasicHttpResponse(originalResponse.getProtocolVersion(),
+ HttpResponse getReconstructedResponse() throws IOException {
+ ensureConsumed();
+ HttpResponse reconstructed = new BasicHttpResponse(response.getProtocolVersion(),
HttpStatus.SC_OK, "Success");
-
- HttpEntity entity = new InputStreamEntity(combinedStream, -1);
- response.setEntity(entity);
- response.setHeaders(originalResponse.getAllHeaders());
-
- return response;
+ reconstructed.setHeaders(response.getAllHeaders());
+ reconstructed.setEntity(new CombinedEntity(resource, instream));
+ return reconstructed;
}
}
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
index afa03f2db..ce343a208 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java
@@ -239,10 +239,9 @@ public class TestCachingHttpClient {
responseProtocolValidationIsCalled();
getMockResponseReader();
- responseIsTooLarge(false);
- byte[] buf = responseReaderReturnsBufferOfSize(100);
-
- generateResource(buf);
+ responseRead();
+ responseLimitReached(false);
+ responseGetResource();
storeInCacheWasCalled();
responseIsGeneratedFromCache();
responseStatusLineIsInspectable();
@@ -553,8 +552,9 @@ public class TestCachingHttpClient {
getCurrentDateReturns(responseDate);
responsePolicyAllowsCaching(true);
getMockResponseReader();
- responseIsTooLarge(true);
- readerReturnsReconstructedResponse();
+ responseRead();
+ responseLimitReached(true);
+ responseGetReconstructed();
replayMocks();
@@ -575,9 +575,9 @@ public class TestCachingHttpClient {
getCurrentDateReturns(responseDate);
responsePolicyAllowsCaching(true);
getMockResponseReader();
- responseIsTooLarge(false);
- byte[] buf = responseReaderReturnsBufferOfSize(100);
- generateResource(buf);
+ responseRead();
+ responseLimitReached(false);
+ responseGetResource();
storeInCacheWasCalled();
responseIsGeneratedFromCache();
responseStatusLineIsInspectable();
@@ -961,7 +961,7 @@ public class TestCachingHttpClient {
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","128");
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result));
}
@@ -974,7 +974,7 @@ public class TestCachingHttpClient {
resp.setHeader("Content-Length","128");
resp.setHeader("Content-Range","bytes 0-127/255");
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result));
}
@@ -986,7 +986,7 @@ public class TestCachingHttpClient {
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Assert.assertTrue(HttpStatus.SC_BAD_GATEWAY == result.getStatusLine().getStatusCode());
}
@@ -998,7 +998,7 @@ public class TestCachingHttpClient {
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result));
}
@@ -1009,7 +1009,7 @@ public class TestCachingHttpClient {
byte[] bytes = HttpTestUtils.getRandomBytes(128);
resp.setEntity(new ByteArrayEntity(bytes));
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result));
}
@@ -1021,7 +1021,7 @@ public class TestCachingHttpClient {
resp.setHeader("Content-Length","foo");
resp.setEntity(new ByteArrayEntity(bytes));
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Assert.assertTrue(HttpTestUtils.semanticallyTransparent(resp, result));
}
@@ -1033,7 +1033,7 @@ public class TestCachingHttpClient {
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
Header ctype = result.getFirstHeader("Content-Type");
Assert.assertEquals("text/plain;charset=UTF-8", ctype.getValue());
}
@@ -1046,7 +1046,7 @@ public class TestCachingHttpClient {
resp.setEntity(new ByteArrayEntity(bytes));
resp.setHeader("Content-Length","256");
- HttpResponse result = impl.correctIncompleteResponse(resp, bytes);
+ HttpResponse result = impl.correctIncompleteResponse(resp, new HeapResource(bytes));
int clen = Integer.parseInt(result.getFirstHeader("Content-Length").getValue());
Assert.assertTrue(clen > 0);
HttpEntity body = result.getEntity();
@@ -1130,6 +1130,7 @@ public class TestCachingHttpClient {
private void getMockResponseReader() {
EasyMock.expect(impl.getResponseReader(
+ EasyMock.anyObject(),
EasyMock.anyObject())).andReturn(mockResponseReader);
}
@@ -1147,19 +1148,20 @@ public class TestCachingHttpClient {
.andReturn(null).anyTimes();
}
- private byte[] responseReaderReturnsBufferOfSize(int bufferSize) {
- byte[] buffer = new byte[bufferSize];
- EasyMock.expect(mockResponseReader.getResponseBytes()).andReturn(buffer);
- return buffer;
+ private void responseRead() throws Exception {
+ mockResponseReader.readResponse();
}
- private void readerReturnsReconstructedResponse() {
- EasyMock.expect(mockResponseReader.getReconstructedResponse()).andReturn(
- mockReconstructedResponse);
+ private void responseLimitReached(boolean limitReached) throws Exception {
+ EasyMock.expect(mockResponseReader.isLimitReached()).andReturn(limitReached);
}
- private void responseIsTooLarge(boolean tooLarge) throws Exception {
- EasyMock.expect(mockResponseReader.isResponseTooLarge()).andReturn(tooLarge);
+ private void responseGetResource() throws Exception {
+ EasyMock.expect(mockResponseReader.getResource()).andReturn(new HeapResource(new byte[] {} ));
+ }
+
+ private void responseGetReconstructed() throws Exception {
+ EasyMock.expect(mockResponseReader.getReconstructedResponse()).andReturn(mockReconstructedResponse);
}
private void backendCallWasMadeWithRequest(HttpRequest request) throws IOException {
@@ -1245,13 +1247,6 @@ public class TestCachingHttpClient {
mockCache.putEntry(theURI, entry);
}
- private void generateResource(byte [] b) throws IOException {
- EasyMock.expect(
- mockResourceFactory.generate(
- EasyMock.anyObject(),
- EasyMock.same(b))).andReturn(new HeapResource(b));
- }
-
private void copyResource() throws IOException {
EasyMock.expect(
mockResourceFactory.copy(
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java
new file mode 100644
index 000000000..e7bf759a0
--- /dev/null
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedEntity.java
@@ -0,0 +1,59 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.impl.client.cache;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.http.client.cache.Resource;
+import org.apache.http.util.EntityUtils;
+import org.easymock.classextension.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestCombinedEntity {
+
+ @Test
+ public void testCombinedEntityBasics() throws Exception {
+ Resource resource = EasyMock.createMock(Resource.class);
+ EasyMock.expect(resource.getInputStream()).andReturn(
+ new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 }));
+ resource.dispose();
+ EasyMock.replay(resource);
+
+ ByteArrayInputStream instream = new ByteArrayInputStream(new byte[] { 6, 7, 8, 9, 10 });
+ CombinedEntity entity = new CombinedEntity(resource, instream);
+ Assert.assertEquals(-1, entity.getContentLength());
+ Assert.assertFalse(entity.isRepeatable());
+ Assert.assertTrue(entity.isStreaming());
+
+ byte[] result = EntityUtils.toByteArray(entity);
+ Assert.assertArrayEquals(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, result);
+
+ EasyMock.verify(resource);
+ }
+
+}
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedInputStream.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedInputStream.java
deleted file mode 100644
index a2bd2fb68..000000000
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCombinedInputStream.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- *
- */
-package org.apache.http.impl.client.cache;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-import org.easymock.classextension.EasyMock;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- */
-public class TestCombinedInputStream {
-
- private InputStream mockInputStream1;
- private InputStream mockInputStream2;
- private CombinedInputStream impl;
-
- @Before
- public void setUp() {
- mockInputStream1 = EasyMock.createMock(InputStream.class);
- mockInputStream2 = EasyMock.createMock(InputStream.class);
-
- impl = new CombinedInputStream(mockInputStream1, mockInputStream2);
- }
-
- @Test
- public void testCreatingInputStreamWithNullInputFails() {
-
- boolean gotex1 = false;
- boolean gotex2 = false;
-
- try {
- impl = new CombinedInputStream(null, mockInputStream2);
- } catch (Exception ex) {
- gotex1 = true;
- }
-
- try {
- impl = new CombinedInputStream(mockInputStream1, null);
- } catch (Exception ex) {
- gotex2 = true;
- }
-
- Assert.assertTrue(gotex1);
- Assert.assertTrue(gotex2);
-
- }
-
- @Test
- public void testAvailableReturnsCorrectSize() throws Exception {
- ByteArrayInputStream s1 = new ByteArrayInputStream(new byte[] { 1, 1, 1, 1, 1 });
- ByteArrayInputStream s2 = new ByteArrayInputStream(new byte[] { 1, 1, 1, 1, 1 });
-
- impl = new CombinedInputStream(s1, s2);
- int avail = impl.available();
-
- Assert.assertEquals(10, avail);
- }
-
- @Test
- public void testFirstEmptyStreamReadsFromOtherStream() throws Exception {
- org.easymock.EasyMock.expect(mockInputStream1.read()).andReturn(-1);
- org.easymock.EasyMock.expect(mockInputStream2.read()).andReturn(500);
-
- replayMocks();
- int result = impl.read();
- verifyMocks();
-
- Assert.assertEquals(500, result);
- }
-
- @Test
- public void testThatWeReadTheFirstInputStream() throws Exception {
- org.easymock.EasyMock.expect(mockInputStream1.read()).andReturn(500);
-
- replayMocks();
- int result = impl.read();
- verifyMocks();
-
- Assert.assertEquals(500, result);
- }
-
- private void verifyMocks() {
- EasyMock.verify(mockInputStream1, mockInputStream2);
- }
-
- private void replayMocks() {
- EasyMock.replay(mockInputStream1, mockInputStream2);
- }
-
-}
diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java
index fed725abb..02141bb2b 100644
--- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java
+++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestSizeLimitedResponseReader.java
@@ -32,8 +32,11 @@ import java.io.InputStream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
+import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
-import org.apache.http.ProtocolVersion;
+import org.apache.http.HttpVersion;
+import org.apache.http.message.BasicRequestLine;
+import org.apache.http.util.EntityUtils;
import org.easymock.classextension.EasyMock;
import org.junit.Assert;
import org.junit.Before;
@@ -41,211 +44,134 @@ import org.junit.Test;
public class TestSizeLimitedResponseReader {
- private static final int MAX_SIZE = 4;
+ private static final long MAX_SIZE = 4;
private SizeLimitedResponseReader impl;
+ private HttpRequest mockRequest;
private HttpResponse mockResponse;
private HttpEntity mockEntity;
- private InputStream mockInputStream;
- private ProtocolVersion mockVersion;
private boolean mockedImpl;
@Before
public void setUp() {
+ mockRequest = EasyMock.createMock(HttpRequest.class);
mockResponse = EasyMock.createMock(HttpResponse.class);
mockEntity = EasyMock.createMock(HttpEntity.class);
- mockInputStream = EasyMock.createMock(InputStream.class);
- mockVersion = EasyMock.createMock(ProtocolVersion.class);
-
}
@Test
public void testLargeResponseIsTooLarge() throws Exception {
-
- responseHasValidEntity();
- entityHasValidContentStream();
- inputStreamReturnsValidBytes(5);
-
- getReader();
-
+ byte[] buf = new byte[] { 1, 2, 3, 4, 5};
+ requestReturnsRequestLine();
+ responseReturnsProtocolVersion();
+ responseReturnsHeaders();
+ responseReturnsContent(new ByteArrayInputStream(buf));
+ initReader();
replayMocks();
- boolean tooLarge = impl.isResponseTooLarge();
- byte[] result = impl.getResponseBytes();
+
+ impl.readResponse();
+ boolean tooLarge = impl.isLimitReached();
+ HttpResponse response = impl.getReconstructedResponse();
+ byte[] result = EntityUtils.toByteArray(response.getEntity());
+
verifyMocks();
-
Assert.assertTrue(tooLarge);
-
- Assert.assertArrayEquals(new byte[] { 1, 1, 1, 1, 1 }, result);
+ Assert.assertArrayEquals(buf, result);
}
@Test
public void testExactSizeResponseIsNotTooLarge() throws Exception {
- responseHasValidEntity();
- entityHasValidContentStream();
- inputStreamReturnsValidBytes(4);
- inputStreamReturnsEndOfStream();
-
- getReader();
+ byte[] buf = new byte[] { 1, 2, 3, 4 };
+ requestReturnsRequestLine();
+ responseReturnsProtocolVersion();
+ responseReturnsHeaders();
+ responseReturnsContent(new ByteArrayInputStream(buf));
+ initReader();
replayMocks();
- boolean tooLarge = impl.isResponseTooLarge();
- byte[] result = impl.getResponseBytes();
+
+ impl.readResponse();
+ boolean tooLarge = impl.isLimitReached();
+ HttpResponse response = impl.getReconstructedResponse();
+ byte[] result = EntityUtils.toByteArray(response.getEntity());
+
verifyMocks();
-
Assert.assertFalse(tooLarge);
-
- Assert.assertArrayEquals(new byte[] { 1, 1, 1, 1 }, result);
+ Assert.assertArrayEquals(buf, result);
}
@Test
public void testSmallResponseIsNotTooLarge() throws Exception {
- responseHasValidEntity();
- entityHasValidContentStream();
-
- org.easymock.EasyMock.expect(mockInputStream.read()).andReturn(1).times(3);
-
- org.easymock.EasyMock.expect(mockInputStream.read()).andReturn(-1).times(2);
-
- getReader();
+ byte[] buf = new byte[] { 1, 2, 3 };
+ requestReturnsRequestLine();
+ responseReturnsProtocolVersion();
+ responseReturnsHeaders();
+ responseReturnsContent(new ByteArrayInputStream(buf));
+ initReader();
replayMocks();
- boolean tooLarge = impl.isResponseTooLarge();
- byte[] result = impl.getResponseBytes();
+
+ impl.readResponse();
+ boolean tooLarge = impl.isLimitReached();
+ HttpResponse response = impl.getReconstructedResponse();
+ byte[] result = EntityUtils.toByteArray(response.getEntity());
verifyMocks();
Assert.assertFalse(tooLarge);
-
- Assert.assertArrayEquals(new byte[] { 1, 1, 1 }, result);
+ Assert.assertArrayEquals(buf, result);
}
@Test
public void testResponseWithNoEntityIsNotTooLarge() throws Exception {
responseHasNullEntity();
- getReader();
+ initReader();
replayMocks();
- boolean tooLarge = impl.isResponseTooLarge();
+ impl.readResponse();
+ boolean tooLarge = impl.isLimitReached();
verifyMocks();
Assert.assertFalse(tooLarge);
}
- @Test
- public void testReconstructedSmallResponseHasCorrectLength() throws Exception {
-
- byte[] expectedArray = new byte[] { 1, 1, 1, 1 };
-
- InputStream stream = new ByteArrayInputStream(new byte[] {});
-
- responseReturnsHeaders();
- responseReturnsProtocolVersion();
-
- getReader();
- mockImplMethods("getResponseBytes", "getContentInputStream");
- getContentInputStreamReturns(stream);
- getResponseBytesReturns(expectedArray);
- replayMocks();
-
- HttpResponse response = impl.getReconstructedResponse();
-
- verifyMocks();
-
- Assert.assertNotNull("Response should not be null", response);
- InputStream resultStream = response.getEntity().getContent();
-
- byte[] buffer = new byte[expectedArray.length];
- resultStream.read(buffer);
-
- Assert.assertArrayEquals(expectedArray, buffer);
+ private void responseReturnsContent(InputStream buffer) throws IOException {
+ EasyMock.expect(mockResponse.getEntity()).andReturn(mockEntity);
+ EasyMock.expect(mockEntity.getContent()).andReturn(buffer);
}
- private void getContentInputStreamReturns(InputStream inputStream) {
- org.easymock.EasyMock.expect(impl.getContentInputStream()).andReturn(inputStream);
- }
-
- @Test
- public void testReconstructedLargeResponseHasCorrectLength() throws Exception {
-
- byte[] expectedArray = new byte[] { 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 };
- byte[] arrayAfterConsumedBytes = new byte[] { 1, 1, 1, 1, 1, 1, 1 };
- byte[] smallArray = new byte[] { 2, 2, 2, 2, };
- InputStream is = new ByteArrayInputStream(arrayAfterConsumedBytes);
-
- responseReturnsHeaders();
- responseReturnsProtocolVersion();
-
- getReader();
- mockImplMethods("getResponseBytes", "getContentInputStream");
- getResponseBytesReturns(smallArray);
- getContentInputStreamReturns(is);
-
- replayMocks();
-
- HttpResponse response = impl.getReconstructedResponse();
-
- verifyMocks();
-
- InputStream resultStream = response.getEntity().getContent();
-
- byte[] buffer = new byte[expectedArray.length];
- resultStream.read(buffer);
-
- Assert.assertArrayEquals(expectedArray, buffer);
- }
-
- private void getResponseBytesReturns(byte[] expectedArray) {
- org.easymock.EasyMock.expect(impl.getResponseBytes()).andReturn(expectedArray);
- }
-
- private void responseReturnsHeaders() {
- org.easymock.EasyMock.expect(mockResponse.getAllHeaders()).andReturn(new Header[] {});
- }
-
- private void entityHasValidContentStream() throws IOException {
- org.easymock.EasyMock.expect(mockEntity.getContent()).andReturn(mockInputStream);
- }
-
- private void inputStreamReturnsEndOfStream() throws IOException {
- org.easymock.EasyMock.expect(mockInputStream.read()).andReturn(-1);
- }
-
- private void responseHasValidEntity() {
- org.easymock.EasyMock.expect(mockResponse.getEntity()).andReturn(mockEntity);
+ private void requestReturnsRequestLine() {
+ EasyMock.expect(mockRequest.getRequestLine()).andReturn(
+ new BasicRequestLine("GET", "/", HttpVersion.HTTP_1_1));
}
private void responseReturnsProtocolVersion() {
- org.easymock.EasyMock.expect(mockResponse.getProtocolVersion()).andReturn(mockVersion);
+ EasyMock.expect(mockResponse.getProtocolVersion()).andReturn(HttpVersion.HTTP_1_1);
}
- private void inputStreamReturnsValidBytes(int times) throws IOException {
- org.easymock.EasyMock.expect(mockInputStream.read()).andReturn(1).times(times);
+ private void responseReturnsHeaders() {
+ EasyMock.expect(mockResponse.getAllHeaders()).andReturn(new Header[] {});
}
private void responseHasNullEntity() {
- org.easymock.EasyMock.expect(mockResponse.getEntity()).andReturn(null);
+ EasyMock.expect(mockResponse.getEntity()).andReturn(null);
}
private void verifyMocks() {
- EasyMock.verify(mockResponse, mockEntity, mockInputStream, mockVersion);
+ EasyMock.verify(mockRequest, mockResponse, mockEntity);
if (mockedImpl) {
EasyMock.verify(impl);
}
}
private void replayMocks() {
- EasyMock.replay(mockResponse, mockEntity, mockInputStream, mockVersion);
+ EasyMock.replay(mockRequest, mockResponse, mockEntity);
if (mockedImpl) {
EasyMock.replay(impl);
}
}
- private void getReader() {
- impl = new SizeLimitedResponseReader(MAX_SIZE, mockResponse);
- }
-
- private void mockImplMethods(String... methods) {
- mockedImpl = true;
- impl = EasyMock.createMockBuilder(SizeLimitedResponseReader.class).withConstructor(
- MAX_SIZE, mockResponse).addMockedMethods(methods).createMock();
+ private void initReader() {
+ impl = new SizeLimitedResponseReader(
+ new HeapResourceFactory(), MAX_SIZE, mockRequest, mockResponse);
}
}