diff --git a/README.md b/README.md
index 93abe15..6dca619 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ repositories {
maven { url 'https://dl.bintray.com/alexeydanilov/maven' }
}
dependencies {
- compile 'com.danikula:videocache:2.1.4'
+ compile 'com.danikula:videocache:2.2.0'
}
```
@@ -34,7 +34,7 @@ private HttpProxyCacheServer getProxy() {
```
To guarantee normal work you should use **single** instance of `HttpProxyCacheServer` for whole app.
-For example you can store shared proxy on your `Application`:
+For example you can store shared proxy in your `Application`:
```java
public class App extends Application {
@@ -59,6 +59,9 @@ More preferable way is use some dependency injector like [Dagger](http://square.
See `sample` app for details.
## Whats new
+### 2.2.0
+- allow to [seek video](https://github.com/danikula/AndroidVideoCache/issues/21) in any position and [fix](https://github.com/danikula/AndroidVideoCache/issues/17) streaming while caching
+
### 2.1.4
- [fix](https://github.com/danikula/AndroidVideoCache/issues/18) available cache percents callback
diff --git a/library/build.gradle b/library/build.gradle
index 6390e75..3bdd043 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -26,7 +26,7 @@ publish {
userOrg = 'alexeydanilov'
groupId = 'com.danikula'
artifactId = 'videocache'
- publishVersion = '2.1.4'
+ publishVersion = '2.2.0'
description = 'Cache support for android VideoView'
website = 'https://github.com/danikula/AndroidVideoCache'
}
diff --git a/library/src/main/java/com/danikula/videocache/ByteArraySource.java b/library/src/main/java/com/danikula/videocache/ByteArraySource.java
index d66efea..8e1ca30 100644
--- a/library/src/main/java/com/danikula/videocache/ByteArraySource.java
+++ b/library/src/main/java/com/danikula/videocache/ByteArraySource.java
@@ -22,7 +22,7 @@ public int read(byte[] buffer) throws ProxyCacheException {
}
@Override
- public int available() throws ProxyCacheException {
+ public int length() throws ProxyCacheException {
return data.length;
}
diff --git a/library/src/main/java/com/danikula/videocache/GetRequest.java b/library/src/main/java/com/danikula/videocache/GetRequest.java
index b154da0..c25464e 100644
--- a/library/src/main/java/com/danikula/videocache/GetRequest.java
+++ b/library/src/main/java/com/danikula/videocache/GetRequest.java
@@ -63,9 +63,9 @@ private String findUri(String request) {
@Override
public String toString() {
return "GetRequest{" +
- "uri='" + uri + '\'' +
- ", rangeOffset=" + rangeOffset +
+ "rangeOffset=" + rangeOffset +
", partial=" + partial +
+ ", uri='" + uri + '\'' +
'}';
}
}
diff --git a/library/src/main/java/com/danikula/videocache/HttpProxyCache.java b/library/src/main/java/com/danikula/videocache/HttpProxyCache.java
index 6bde7be..61681bd 100644
--- a/library/src/main/java/com/danikula/videocache/HttpProxyCache.java
+++ b/library/src/main/java/com/danikula/videocache/HttpProxyCache.java
@@ -7,6 +7,8 @@
import java.io.OutputStream;
import java.net.Socket;
+import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE;
+
/**
* {@link ProxyCache} that read http url and writes data to {@link Socket}
*
@@ -14,6 +16,8 @@
*/
class HttpProxyCache extends ProxyCache {
+ private static final float NO_CACHE_BARRIER = .2f;
+
private final HttpUrlSource source;
private final FileCache cache;
private CacheListener listener;
@@ -30,27 +34,29 @@ public void registerCacheListener(CacheListener cacheListener) {
public void processRequest(GetRequest request, Socket socket) throws IOException, ProxyCacheException {
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
- byte[] buffer = new byte[ProxyCacheUtils.DEFAULT_BUFFER_SIZE];
- int readBytes;
- boolean headersWrote = false;
+ String responseHeaders = newResponseHeaders(request);
+ out.write(responseHeaders.getBytes("UTF-8"));
+
long offset = request.rangeOffset;
- while ((readBytes = read(buffer, offset, buffer.length)) != -1) {
- // tiny optimization: to prevent HEAD request in source for content-length. content-length 'll available after reading source
- if (!headersWrote) {
- String responseHeaders = newResponseHeaders(request);
- out.write(responseHeaders.getBytes("UTF-8"));
- headersWrote = true;
- }
- out.write(buffer, 0, readBytes);
- offset += readBytes;
+ if (isUseCache(request)) {
+ responseWithCache(out, offset);
+ } else {
+ responseWithoutCache(out, offset);
}
- out.flush();
+ }
+
+ private boolean isUseCache(GetRequest request) throws ProxyCacheException {
+ int sourceLength = source.length();
+ boolean sourceLengthKnown = sourceLength > 0;
+ int cacheAvailable = cache.available();
+ // do not use cache for partial requests which too far from available cache. It seems user seek video.
+ return !sourceLengthKnown || !request.partial || request.rangeOffset <= cacheAvailable + sourceLength * NO_CACHE_BARRIER;
}
private String newResponseHeaders(GetRequest request) throws IOException, ProxyCacheException {
String mime = source.getMime();
boolean mimeKnown = !TextUtils.isEmpty(mime);
- int length = cache.isCompleted() ? cache.available() : source.available();
+ int length = cache.isCompleted() ? cache.available() : source.length();
boolean lengthKnown = length >= 0;
long contentLength = request.partial ? length - request.rangeOffset : length;
boolean addRange = lengthKnown && request.partial;
@@ -64,6 +70,32 @@ private String newResponseHeaders(GetRequest request) throws IOException, ProxyC
.toString();
}
+ private void responseWithCache(OutputStream out, long offset) throws ProxyCacheException, IOException {
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int readBytes;
+ while ((readBytes = read(buffer, offset, buffer.length)) != -1) {
+ out.write(buffer, 0, readBytes);
+ offset += readBytes;
+ }
+ out.flush();
+ }
+
+ private void responseWithoutCache(OutputStream out, long offset) throws ProxyCacheException, IOException {
+ try {
+ HttpUrlSource source = new HttpUrlSource(this.source);
+ source.open((int) offset);
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int readBytes;
+ while ((readBytes = source.read(buffer)) != -1) {
+ out.write(buffer, 0, readBytes);
+ offset += readBytes;
+ }
+ out.flush();
+ } finally {
+ source.close();
+ }
+ }
+
@Override
protected void onCachePercentsAvailableChanged(int percents) {
if (listener != null) {
diff --git a/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java b/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java
index 49920ae..53f89d1 100644
--- a/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java
+++ b/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java
@@ -79,7 +79,7 @@ public HttpProxyCacheServer(FileNameGenerator fileNameGenerator) {
private void makeSureServerWorks() {
int maxPingAttempts = 3;
- int delay = 100;
+ int delay = 200;
int pingAttempts = 0;
while (pingAttempts < maxPingAttempts) {
try {
@@ -92,13 +92,13 @@ private void makeSureServerWorks() {
SystemClock.sleep(delay);
delay *= 2;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
- Log.e(LOG_TAG, "Error pinging server. Shutdown it... If you see this message, please, email me danikula@gmail.com", e);
+ Log.e(LOG_TAG, "Error pinging server [attempt: " + pingAttempts + ", timeout: " + delay + "]. ", e);
}
}
- if (!pinged) {
- shutdown();
- }
+ Log.e(LOG_TAG, "Shutdown server… Error pinging server [attempt: " + pingAttempts + ", timeout: " + delay + "]. " +
+ "If you see this message, please, email me danikula@gmail.com");
+ shutdown();
}
private boolean pingServer() throws ProxyCacheException {
@@ -212,7 +212,7 @@ private void processSocket(Socket socket) {
} catch (SocketException e) {
// There is no way to determine that client closed connection http://stackoverflow.com/a/10241044/999458
// So just to prevent log flooding don't log stacktrace
- Log.d(LOG_TAG, "Client communication problem. It seems client closed connection");
+ Log.d(LOG_TAG, "Closing socket… Socket is closed by client.");
} catch (ProxyCacheException | IOException e) {
onError(new ProxyCacheException("Error processing request", e));
} finally {
@@ -262,7 +262,7 @@ private void closeSocketInput(Socket socket) {
} catch (SocketException e) {
// There is no way to determine that client closed connection http://stackoverflow.com/a/10241044/999458
// So just to prevent log flooding don't log stacktrace
- Log.d(LOG_TAG, "Error closing client's input stream: it seems client closed connection");
+ Log.d(LOG_TAG, "Releasing input stream… Socket is closed by client.");
} catch (IOException e) {
onError(new ProxyCacheException("Error closing socket input stream", e));
}
diff --git a/library/src/main/java/com/danikula/videocache/HttpUrlSource.java b/library/src/main/java/com/danikula/videocache/HttpUrlSource.java
index a8ec0da..cc8bd22 100644
--- a/library/src/main/java/com/danikula/videocache/HttpUrlSource.java
+++ b/library/src/main/java/com/danikula/videocache/HttpUrlSource.java
@@ -29,7 +29,7 @@ public class HttpUrlSource implements Source {
public final String url;
private HttpURLConnection connection;
private InputStream inputStream;
- private volatile int available = Integer.MIN_VALUE;
+ private volatile int length = Integer.MIN_VALUE;
private volatile String mime;
public HttpUrlSource(String url) {
@@ -41,12 +41,18 @@ public HttpUrlSource(String url, String mime) {
this.mime = mime;
}
+ public HttpUrlSource(HttpUrlSource source) {
+ this.url = source.url;
+ this.mime = source.mime;
+ this.length = source.length;
+ }
+
@Override
- public synchronized int available() throws ProxyCacheException {
- if (available == Integer.MIN_VALUE) {
+ public synchronized int length() throws ProxyCacheException {
+ if (length == Integer.MIN_VALUE) {
fetchContentInfo();
}
- return available;
+ return length;
}
@Override
@@ -55,7 +61,7 @@ public void open(int offset) throws ProxyCacheException {
connection = openConnection(offset, "GET", -1);
mime = connection.getContentType();
inputStream = new BufferedInputStream(connection.getInputStream(), DEFAULT_BUFFER_SIZE);
- available = readSourceAvailableBytes(connection, offset, connection.getResponseCode());
+ length = readSourceAvailableBytes(connection, offset, connection.getResponseCode());
} catch (IOException e) {
throw new ProxyCacheException("Error opening connection for " + url + " with offset " + offset, e);
}
@@ -64,7 +70,7 @@ public void open(int offset) throws ProxyCacheException {
private int readSourceAvailableBytes(HttpURLConnection connection, int offset, int responseCode) throws IOException {
int contentLength = connection.getContentLength();
return responseCode == HTTP_OK ? contentLength
- : responseCode == HTTP_PARTIAL ? contentLength + offset : available;
+ : responseCode == HTTP_PARTIAL ? contentLength + offset : length;
}
@Override
@@ -94,10 +100,10 @@ private void fetchContentInfo() throws ProxyCacheException {
InputStream inputStream = null;
try {
urlConnection = openConnection(0, "HEAD", 10000);
- available = urlConnection.getContentLength();
+ length = urlConnection.getContentLength();
mime = urlConnection.getContentType();
inputStream = urlConnection.getInputStream();
- Log.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + available);
+ Log.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + length);
} catch (IOException e) {
Log.e(LOG_TAG, "Error fetching info from " + url, e);
} finally {
diff --git a/library/src/main/java/com/danikula/videocache/ProxyCache.java b/library/src/main/java/com/danikula/videocache/ProxyCache.java
index 1ec1613..2e7ef45 100644
--- a/library/src/main/java/com/danikula/videocache/ProxyCache.java
+++ b/library/src/main/java/com/danikula/videocache/ProxyCache.java
@@ -119,7 +119,7 @@ private void readSource() {
try {
offset = cache.available();
source.open(offset);
- sourceAvailable = source.available();
+ sourceAvailable = source.length();
byte[] buffer = new byte[ProxyCacheUtils.DEFAULT_BUFFER_SIZE];
int readBytes;
while ((readBytes = source.read(buffer)) != -1) {
@@ -144,7 +144,7 @@ private void readSource() {
private void tryComplete() throws ProxyCacheException {
synchronized (stopLock) {
- if (!isStopped() && cache.available() == source.available()) {
+ if (!isStopped() && cache.available() == source.length()) {
cache.complete();
}
}
diff --git a/library/src/main/java/com/danikula/videocache/Source.java b/library/src/main/java/com/danikula/videocache/Source.java
index 1aa5fbc..6740486 100644
--- a/library/src/main/java/com/danikula/videocache/Source.java
+++ b/library/src/main/java/com/danikula/videocache/Source.java
@@ -16,12 +16,12 @@ public interface Source {
void open(int offset) throws ProxyCacheException;
/**
- * Returns available bytes or negative value if available bytes count is unknown.
+ * Returns length bytes or negative value if length is unknown.
*
- * @return bytes available
+ * @return bytes length
* @throws ProxyCacheException if error occur while fetching source data.
*/
- int available() throws ProxyCacheException;
+ int length() throws ProxyCacheException;
/**
* Read data to byte buffer from source with current offset.
diff --git a/sample/build.gradle b/sample/build.gradle
index 5d4a212..89d6c83 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -39,7 +39,7 @@ dependencies {
// compile project(':library')
compile 'com.android.support:support-v4:23.0.1'
compile 'org.androidannotations:androidannotations-api:3.3.2'
- compile 'com.danikula:videocache:2.1.4'
+ compile 'com.danikula:videocache:2.2.0'
compile 'com.viewpagerindicator:library:2.4.2-SNAPSHOT@aar'
apt 'org.androidannotations:androidannotations:3.3.2'
}
diff --git a/test/src/test/java/com/danikula/videocache/HttpProxyCacheServerTest.java b/test/src/test/java/com/danikula/videocache/HttpProxyCacheServerTest.java
index f58a616..8aaa9da 100644
--- a/test/src/test/java/com/danikula/videocache/HttpProxyCacheServerTest.java
+++ b/test/src/test/java/com/danikula/videocache/HttpProxyCacheServerTest.java
@@ -98,7 +98,7 @@ public void testProxyFullResponseWithRedirect() throws Exception {
@Test
public void testProxyPartialResponse() throws Exception {
- int offset = 42000;
+ int offset = 18000;
Pair response = readProxyData(HTTP_DATA_BIG_URL, offset);
assertThat(response.second.code).isEqualTo(206);
@@ -116,7 +116,7 @@ public void testProxyPartialResponse() throws Exception {
@Test
public void testProxyPartialResponseWithRedirect() throws Exception {
- int offset = 42000;
+ int offset = 18000;
Pair response = readProxyData(HTTP_DATA_BIG_URL_ONE_REDIRECT, offset);
assertThat(response.second.code).isEqualTo(206);
diff --git a/test/src/test/java/com/danikula/videocache/HttpProxyCacheTest.java b/test/src/test/java/com/danikula/videocache/HttpProxyCacheTest.java
new file mode 100644
index 0000000..b1b2d7b
--- /dev/null
+++ b/test/src/test/java/com/danikula/videocache/HttpProxyCacheTest.java
@@ -0,0 +1,75 @@
+package com.danikula.videocache;
+
+import com.danikula.videocache.support.ProxyCacheTestUtils;
+import com.danikula.videocache.support.Response;
+import com.danikula.videocache.test.BuildConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.robolectric.RobolectricGradleTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.io.ByteArrayOutputStream;
+import java.net.Socket;
+
+import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL;
+import static com.danikula.videocache.support.ProxyCacheTestUtils.loadTestData;
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test {@link HttpProxyCache}.
+ *
+ * @author Alexey Danilov (danikula@gmail.com).
+ */
+@RunWith(RobolectricGradleTestRunner.class)
+@Config(constants = BuildConfig.class, emulateSdk = BuildConfig.MIN_SDK_VERSION)
+public class HttpProxyCacheTest {
+
+ @Test
+ public void testProcessRequestNoCache() throws Exception {
+ HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL);
+ FileCache cache = new FileCache(ProxyCacheTestUtils.newCacheFile());
+ HttpProxyCache proxyCache = new HttpProxyCache(source, cache);
+ GetRequest request = new GetRequest("GET /" + HTTP_DATA_URL + " HTTP/1.1");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Socket socket = mock(Socket.class);
+ when(socket.getOutputStream()).thenReturn(out);
+
+ proxyCache.processRequest(request, socket);
+ Response response = new Response(out.toByteArray());
+
+ assertThat(response.data).isEqualTo(loadTestData());
+ assertThat(response.code).isEqualTo(200);
+ assertThat(response.contentLength).isEqualTo(ProxyCacheTestUtils.HTTP_DATA_SIZE);
+ assertThat(response.contentType).isEqualTo("image/jpeg");
+ }
+
+ @Test
+ public void testProcessPartialRequestWithoutCache() throws Exception {
+ HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL);
+ FileCache fileCache = new FileCache(ProxyCacheTestUtils.newCacheFile());
+ FileCache spyFileCache = Mockito.spy(fileCache);
+ doThrow(new RuntimeException()).when(spyFileCache).read(any(byte[].class), anyLong(), anyInt());
+ HttpProxyCache proxyCache = new HttpProxyCache(source, spyFileCache);
+ GetRequest request = new GetRequest("GET /" + HTTP_DATA_URL + " HTTP/1.1\nRange: bytes=2000-");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Socket socket = mock(Socket.class);
+ when(socket.getOutputStream()).thenReturn(out);
+
+ proxyCache.processRequest(request, socket);
+ Response response = new Response(out.toByteArray());
+
+ byte[] fullData = loadTestData();
+ byte[] partialData = new byte[fullData.length - 2000];
+ System.arraycopy(fullData, 2000, partialData, 0, partialData.length);
+ assertThat(response.data).isEqualTo(partialData);
+ assertThat(response.code).isEqualTo(206);
+ }
+}
diff --git a/test/src/test/java/com/danikula/videocache/HttpUrlSourceTest.java b/test/src/test/java/com/danikula/videocache/HttpUrlSourceTest.java
index e4e2ea7..76162fb 100644
--- a/test/src/test/java/com/danikula/videocache/HttpUrlSourceTest.java
+++ b/test/src/test/java/com/danikula/videocache/HttpUrlSourceTest.java
@@ -63,14 +63,14 @@ public void testHttpUrlSourceWithOffset() throws Exception {
@Test
public void testFetchContentLength() throws Exception {
Source source = new HttpUrlSource(HTTP_DATA_URL);
- assertThat(source.available()).isEqualTo(loadAssetFile(ASSETS_DATA_NAME).length);
+ assertThat(source.length()).isEqualTo(loadAssetFile(ASSETS_DATA_NAME).length);
}
@Test
public void testFetchInfoWithRedirect() throws Exception {
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_ONE_REDIRECT);
source.open(0);
- int available = source.available();
+ int available = source.length();
String mime = source.getMime();
source.close();
diff --git a/test/src/test/java/com/danikula/videocache/support/AngryHttpUrlSource.java b/test/src/test/java/com/danikula/videocache/support/AngryHttpUrlSource.java
index 985dc94..951d725 100644
--- a/test/src/test/java/com/danikula/videocache/support/AngryHttpUrlSource.java
+++ b/test/src/test/java/com/danikula/videocache/support/AngryHttpUrlSource.java
@@ -11,7 +11,7 @@
public class AngryHttpUrlSource implements Source {
@Override
- public int available() throws ProxyCacheException {
+ public int length() throws ProxyCacheException {
throw new IllegalStateException();
}
diff --git a/test/src/test/java/com/danikula/videocache/support/ProxyCacheTestUtils.java b/test/src/test/java/com/danikula/videocache/support/ProxyCacheTestUtils.java
index 8acbee5..ba0c0dd 100644
--- a/test/src/test/java/com/danikula/videocache/support/ProxyCacheTestUtils.java
+++ b/test/src/test/java/com/danikula/videocache/support/ProxyCacheTestUtils.java
@@ -52,6 +52,10 @@ public static Response readProxyResponse(HttpProxyCacheServer proxy, String url,
}
}
+ public static byte[] loadTestData() throws IOException {
+ return loadAssetFile(ASSETS_DATA_NAME);
+ }
+
public static byte[] loadAssetFile(String name) throws IOException {
InputStream in = RuntimeEnvironment.application.getResources().getAssets().open(name);
ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/test/src/test/java/com/danikula/videocache/support/Response.java b/test/src/test/java/com/danikula/videocache/support/Response.java
index 6b68b64..158ed15 100644
--- a/test/src/test/java/com/danikula/videocache/support/Response.java
+++ b/test/src/test/java/com/danikula/videocache/support/Response.java
@@ -1,14 +1,27 @@
package com.danikula.videocache.support;
+import android.text.TextUtils;
+
+import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.StringReader;
import java.net.HttpURLConnection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class Response {
+ private static final String CONTENT_TYPE_HEADER = "Content-Type";
+ private static final String CONTENT_LENGTH_HEADER = "Content-Length";
+ private static final Pattern STATUS_CODE_PATTERN = Pattern.compile("HTTP/1.1 (\\d{3}) ");
+
public final int code;
public final byte[] data;
public final int contentLength;
@@ -22,4 +35,33 @@ public Response(HttpURLConnection connection) throws IOException {
this.headers = connection.getHeaderFields();
this.data = ByteStreams.toByteArray(connection.getInputStream());
}
+
+ public Response(byte[] responseData) throws IOException {
+ int read = 0;
+ BufferedReader reader = new BufferedReader(new StringReader(new String(responseData, "ascii")));
+ String statusLine = reader.readLine();
+ read += statusLine.length() + 1;
+ Matcher matcher = STATUS_CODE_PATTERN.matcher(statusLine);
+ boolean hasCode = matcher.find();
+ Preconditions.checkArgument(hasCode, "Status code not found in `" + statusLine + "`");
+ this.code = Integer.parseInt(matcher.group(1));
+
+ String header;
+ this.headers = new HashMap<>();
+ while (!TextUtils.isEmpty(header = reader.readLine())) {
+ read += header.length() + 1;
+ String[] keyValue = header.split(":");
+ String headerName = keyValue[0].trim();
+ String headerValue = keyValue[1].trim();
+ headers.put(headerName, Collections.singletonList(headerValue));
+ }
+ read++;
+
+ this.contentType = headers.containsKey(CONTENT_TYPE_HEADER) ? headers.get(CONTENT_TYPE_HEADER).get(0) : null;
+ this.contentLength = headers.containsKey(CONTENT_LENGTH_HEADER) ? Integer.parseInt(headers.get(CONTENT_LENGTH_HEADER).get(0)) : -1;
+
+ int bodySize = responseData.length - read;
+ this.data = new byte[bodySize];
+ System.arraycopy(responseData, read, data, 0, bodySize);
+ }
}
\ No newline at end of file