Commit f2cf086d by falhassen Committed by Oliver Woodman

Fix content length calculation for gzipped files

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=134011959
parent 57a2749a
...@@ -109,7 +109,7 @@ public final class CronetDataSourceTest { ...@@ -109,7 +109,7 @@ public final class CronetDataSourceTest {
@Mock @Mock
private Predicate<String> mockContentTypePredicate; private Predicate<String> mockContentTypePredicate;
@Mock @Mock
private TransferListener mockTransferListener; private TransferListener<CronetDataSource> mockTransferListener;
@Mock @Mock
private Clock mockClock; private Clock mockClock;
@Mock @Mock
...@@ -172,8 +172,8 @@ public final class CronetDataSourceTest { ...@@ -172,8 +172,8 @@ public final class CronetDataSourceTest {
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testOpeningTwiceThrows() throws HttpDataSourceException, IllegalStateException { public void testOpeningTwiceThrows() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
assertConnectionState(CronetDataSource.IDLE_CONNECTION); assertConnectionState(CronetDataSource.IDLE_CONNECTION);
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
...@@ -183,7 +183,7 @@ public final class CronetDataSourceTest { ...@@ -183,7 +183,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testCallbackFromPreviousRequest() throws HttpDataSourceException { public void testCallbackFromPreviousRequest() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
dataSourceUnderTest.close(); dataSourceUnderTest.close();
...@@ -217,7 +217,7 @@ public final class CronetDataSourceTest { ...@@ -217,7 +217,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestStartCalled() throws HttpDataSourceException { public void testRequestStartCalled() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
verify(mockCronetEngine).createRequest( verify(mockCronetEngine).createRequest(
...@@ -234,7 +234,7 @@ public final class CronetDataSourceTest { ...@@ -234,7 +234,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestHeadersSet() throws HttpDataSourceException { public void testRequestHeadersSet() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
testResponseHeader.put("Content-Length", Long.toString(5000L)); testResponseHeader.put("Content-Length", Long.toString(5000L));
...@@ -252,13 +252,29 @@ public final class CronetDataSourceTest { ...@@ -252,13 +252,29 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestOpen() throws HttpDataSourceException { public void testRequestOpen() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testDataSpec)); assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testDataSpec));
assertConnectionState(CronetDataSource.OPEN_CONNECTION); assertConnectionState(CronetDataSource.OPEN_CONNECTION);
verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec); verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec);
} }
@Test
public void testRequestOpenGzippedCompressedReturnsDataSpecLength()
throws HttpDataSourceException {
testResponseHeader.put("Content-Encoding", "gzip");
testUrlResponseInfo = createUrlResponseInfo(200); // statusCode
mockResponseStartSuccess();
// Data spec's requested length, 5000. Test response's length, 16,000.
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
assertEquals(5000 /* contentLength */, dataSourceUnderTest.open(testDataSpec));
assertConnectionState(CronetDataSource.OPEN_CONNECTION);
verify(mockTransferListener).onTransferStart(dataSourceUnderTest, testDataSpec);
}
@Test @Test
public void testRequestOpenFail() { public void testRequestOpenFail() {
mockResponseStartFailure(); mockResponseStartFailure();
...@@ -295,7 +311,7 @@ public final class CronetDataSourceTest { ...@@ -295,7 +311,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestOpenValidatesStatusCode() { public void testRequestOpenValidatesStatusCode() {
mockResponesStartSuccess(); mockResponseStartSuccess();
testUrlResponseInfo = createUrlResponseInfo(500); // statusCode testUrlResponseInfo = createUrlResponseInfo(500); // statusCode
try { try {
...@@ -312,7 +328,7 @@ public final class CronetDataSourceTest { ...@@ -312,7 +328,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestOpenValidatesContentTypePredicate() { public void testRequestOpenValidatesContentTypePredicate() {
mockResponesStartSuccess(); mockResponseStartSuccess();
when(mockContentTypePredicate.evaluate(anyString())).thenReturn(false); when(mockContentTypePredicate.evaluate(anyString())).thenReturn(false);
try { try {
...@@ -329,7 +345,7 @@ public final class CronetDataSourceTest { ...@@ -329,7 +345,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestOpenValidatesContentLength() { public void testRequestOpenValidatesContentLength() {
mockResponesStartSuccess(); mockResponseStartSuccess();
// Data spec's requested length, 5000. Test response's length, 16,000. // Data spec's requested length, 5000. Test response's length, 16,000.
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
...@@ -348,7 +364,7 @@ public final class CronetDataSourceTest { ...@@ -348,7 +364,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testPostRequestOpen() throws HttpDataSourceException { public void testPostRequestOpen() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
dataSourceUnderTest.setRequestProperty("Content-Type", TEST_CONTENT_TYPE); dataSourceUnderTest.setRequestProperty("Content-Type", TEST_CONTENT_TYPE);
assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testPostDataSpec)); assertEquals(TEST_CONTENT_LENGTH, dataSourceUnderTest.open(testPostDataSpec));
...@@ -358,7 +374,7 @@ public final class CronetDataSourceTest { ...@@ -358,7 +374,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testPostRequestOpenValidatesContentType() { public void testPostRequestOpenValidatesContentType() {
mockResponesStartSuccess(); mockResponseStartSuccess();
try { try {
dataSourceUnderTest.open(testPostDataSpec); dataSourceUnderTest.open(testPostDataSpec);
...@@ -370,7 +386,7 @@ public final class CronetDataSourceTest { ...@@ -370,7 +386,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testPostRequestOpenRejects307Redirects() { public void testPostRequestOpenRejects307Redirects() {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockResponseStartRedirect(); mockResponseStartRedirect();
try { try {
...@@ -384,7 +400,7 @@ public final class CronetDataSourceTest { ...@@ -384,7 +400,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testRequestReadTwice() throws HttpDataSourceException { public void testRequestReadTwice() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadSuccess(); mockReadSuccess();
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
...@@ -406,7 +422,7 @@ public final class CronetDataSourceTest { ...@@ -406,7 +422,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testSecondRequestNoContentLength() throws HttpDataSourceException { public void testSecondRequestNoContentLength() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadSuccess(); mockReadSuccess();
byte[] returnedBuffer = new byte[8]; byte[] returnedBuffer = new byte[8];
...@@ -437,7 +453,23 @@ public final class CronetDataSourceTest { ...@@ -437,7 +453,23 @@ public final class CronetDataSourceTest {
@Test @Test
public void testReadWithOffset() throws HttpDataSourceException { public void testReadWithOffset() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadSuccess();
dataSourceUnderTest.open(testDataSpec);
byte[] returnedBuffer = new byte[16];
int bytesRead = dataSourceUnderTest.read(returnedBuffer, 8, 8);
assertArrayEquals(prefixZeros(buildTestDataArray(0, 8), 16), returnedBuffer);
assertEquals(8, bytesRead);
verify(mockTransferListener).onBytesTransferred(dataSourceUnderTest, 8);
}
@Test
public void testReadWithUnsetLength() throws HttpDataSourceException {
testResponseHeader.remove("Content-Length");
testUrlResponseInfo = createUrlResponseInfo(200); // statusCode
mockResponseStartSuccess();
mockReadSuccess(); mockReadSuccess();
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
...@@ -451,7 +483,7 @@ public final class CronetDataSourceTest { ...@@ -451,7 +483,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testReadReturnsWhatItCan() throws HttpDataSourceException { public void testReadReturnsWhatItCan() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadSuccess(); mockReadSuccess();
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
...@@ -465,7 +497,7 @@ public final class CronetDataSourceTest { ...@@ -465,7 +497,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testClosedMeansClosed() throws HttpDataSourceException { public void testClosedMeansClosed() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadSuccess(); mockReadSuccess();
int bytesRead = 0; int bytesRead = 0;
...@@ -493,7 +525,7 @@ public final class CronetDataSourceTest { ...@@ -493,7 +525,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testOverread() throws HttpDataSourceException { public void testOverread() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadSuccess(); mockReadSuccess();
// Ask for 16 bytes // Ask for 16 bytes
...@@ -680,7 +712,7 @@ public final class CronetDataSourceTest { ...@@ -680,7 +712,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testExceptionFromTransferListener() throws HttpDataSourceException { public void testExceptionFromTransferListener() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
// Make mockTransferListener throw an exception in CronetDataSource.close(). Ensure that // Make mockTransferListener throw an exception in CronetDataSource.close(). Ensure that
// the subsequent open() call succeeds. // the subsequent open() call succeeds.
...@@ -699,7 +731,7 @@ public final class CronetDataSourceTest { ...@@ -699,7 +731,7 @@ public final class CronetDataSourceTest {
@Test @Test
public void testReadFailure() throws HttpDataSourceException { public void testReadFailure() throws HttpDataSourceException {
mockResponesStartSuccess(); mockResponseStartSuccess();
mockReadFailure(); mockReadFailure();
dataSourceUnderTest.open(testDataSpec); dataSourceUnderTest.open(testDataSpec);
...@@ -726,7 +758,7 @@ public final class CronetDataSourceTest { ...@@ -726,7 +758,7 @@ public final class CronetDataSourceTest {
}).when(mockUrlRequest).getStatus(any(UrlRequest.StatusListener.class)); }).when(mockUrlRequest).getStatus(any(UrlRequest.StatusListener.class));
} }
private void mockResponesStartSuccess() { private void mockResponseStartSuccess() {
doAnswer(new Answer<Object>() { doAnswer(new Answer<Object>() {
@Override @Override
public Object answer(InvocationOnMock invocation) throws Throwable { public Object answer(InvocationOnMock invocation) throws Throwable {
......
...@@ -300,15 +300,20 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou ...@@ -300,15 +300,20 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou
try { try {
validateResponse(info); validateResponse(info);
responseInfo = info; responseInfo = info;
// Check content length.
contentLength = getContentLength(info.getAllHeaders()); if (isCompressed(info)) {
// If a specific length is requested and a specific length is returned but the 2 don't match contentLength = currentDataSpec.length;
// it's an error. } else {
if (currentDataSpec.length != C.LENGTH_UNSET // Check content length.
&& contentLength != C.LENGTH_UNSET contentLength = getContentLength(info.getAllHeaders());
&& currentDataSpec.length != contentLength) { // If a specific length is requested and a specific length is returned but the 2 don't match
throw new OpenException("Content length did not match requested length", currentDataSpec, // it's an error.
getCurrentRequestStatus()); if (currentDataSpec.length != C.LENGTH_UNSET
&& contentLength != C.LENGTH_UNSET
&& currentDataSpec.length != contentLength) {
throw new OpenException("Content length did not match requested length", currentDataSpec,
getCurrentRequestStatus());
}
} }
if (contentLength > 0) { if (contentLength > 0) {
...@@ -326,6 +331,23 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou ...@@ -326,6 +331,23 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou
} }
} }
/**
* Returns {@code true} iff the content is compressed.
*
* <p>If {@code true}, clients cannot use the value of content length from the request headers to
* read the data, since Cronet returns the uncompressed data and this content length reflects the
* compressed content length.
*/
private boolean isCompressed(UrlResponseInfo info) {
for (Map.Entry<String, String> entry : info.getAllHeadersAsList()) {
if (entry.getKey().equalsIgnoreCase("Content-Encoding")) {
return !entry.getValue().equalsIgnoreCase("identity");
}
}
return false;
}
private void validateResponse(UrlResponseInfo info) throws HttpDataSourceException { private void validateResponse(UrlResponseInfo info) throws HttpDataSourceException {
// Check for a valid response code. // Check for a valid response code.
int responseCode = info.getHttpStatusCode(); int responseCode = info.getHttpStatusCode();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment